All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.fabric8.kubernetes.client.internal.PKCS1Util Maven / Gradle / Ivy

The newest version!
/*
 * Copyright (C) 2015 Red Hat, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *         http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package io.fabric8.kubernetes.client.internal;

import io.fabric8.kubernetes.client.KubernetesClientException;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.math.BigInteger;
import java.security.GeneralSecurityException;
import java.security.KeyPairGenerator;
import java.security.Provider;
import java.security.Security;
import java.security.interfaces.ECPublicKey;
import java.security.spec.ECGenParameterSpec;
import java.security.spec.ECParameterSpec;
import java.security.spec.ECPrivateKeySpec;
import java.security.spec.RSAPrivateCrtKeySpec;

/**
 * This code is inspired and taken over from net.auth.core:oauth
 * (albeit in a highly stripped variation):
 * 

* Source is from http://oauth.googlecode.com/svn/code/java/ which is licensed * under the APL (http://oauth.googlecode.com/svn/code/java/LICENSE.txt) *

* All credits go to the original author (zhang) * * @author roland * @since 30/09/15 */ class PKCS1Util { private PKCS1Util() { } public static RSAPrivateCrtKeySpec decodePKCS1(byte[] keyBytes) throws IOException { DerParser parser = new DerParser(keyBytes); Asn1Object sequence = parser.read(); sequence.validateSequence(); parser = new DerParser(sequence.getValue()); parser.read(); return new RSAPrivateCrtKeySpec(next(parser), next(parser), next(parser), next(parser), next(parser), next(parser), next(parser), next(parser)); } // ========================================================================================== private static BigInteger next(DerParser parser) throws IOException { return parser.read().getInteger(); } static class DerParser { private final static int SEQUENCE = 0x10; private final static int INTEGER = 0x02; private final static int OBJECT_IDENTIFIER = 0x06; private InputStream in; DerParser(byte[] bytes) { this.in = new ByteArrayInputStream(bytes); } Asn1Object read() throws IOException { int tag = in.read(); if (tag == -1) { throw new IOException("Invalid DER: stream too short, missing tag"); } int length = getLength(); byte[] value = new byte[length]; if (in.read(value) < length) { throw new IOException("Invalid DER: stream too short, missing value"); } return new Asn1Object(tag, value); } private int getLength() throws IOException { int i = in.read(); if (i == -1) { throw new IOException("Invalid DER: length missing"); } if ((i & ~0x7F) == 0) { return i; } int num = i & 0x7F; if (i >= 0xFF || num > 4) { throw new IOException("Invalid DER: length field too big (" + i + ")"); } byte[] bytes = new byte[num]; if (in.read(bytes) < num) { throw new IOException("Invalid DER: length too short"); } return new BigInteger(1, bytes).intValue(); } } static class Asn1Object { private final int type; private final byte[] value; private final int tag; public Asn1Object(int tag, byte[] value) { this.tag = tag; this.type = tag & 0x1F; this.value = value; } public byte[] getValue() { return value; } BigInteger getInteger() throws IOException { if (type != 0x02) { throw new IOException("Invalid DER: object is not integer"); //$NON-NLS-1$ } return new BigInteger(value); } void validateSequence() throws IOException { if (type != 0x10) { throw new IOException("Invalid DER: not a sequence"); } if ((tag & 0x20) != 0x20) { throw new IOException("Invalid DER: can't parse primitive entity"); } } } // adapted from io.vertx.core.net.impl.pkcs1.PrivateKeyParser public static ECPrivateKeySpec getECKeySpec(byte[] keyBytes) throws IOException { DerParser parser = new DerParser(keyBytes); Asn1Object sequence = parser.read(); if (sequence.type != DerParser.SEQUENCE) { throw new KubernetesClientException("Invalid DER: not a sequence"); } // Parse inside the sequence parser = new DerParser(sequence.value); Asn1Object version = parser.read(); if (version.type != DerParser.INTEGER) { throw new KubernetesClientException(String.format( "Invalid DER: 'version' field must be of type INTEGER (2) but found type `%d`", version.type)); } else if (version.getInteger().intValue() != 1) { throw new KubernetesClientException(String.format( "Invalid DER: expected 'version' field to have value '1' but found '%d'", version.getInteger().intValue())); } byte[] privateValue = parser.read().getValue(); parser = new DerParser(parser.read().getValue()); Asn1Object params = parser.read(); // ECParameters are mandatory according to RFC 5915, Section 3 if (params.type != DerParser.OBJECT_IDENTIFIER) { throw new KubernetesClientException(String.format( "Invalid DER: expected to find an OBJECT_IDENTIFIER (6) in 'parameters' but found type '%d'", params.type)); } byte[] namedCurveOid = params.getValue(); ECParameterSpec spec = getECParameterSpec(oidToString(namedCurveOid)); return new ECPrivateKeySpec(new BigInteger(1, privateValue), spec); } private static ECParameterSpec getECParameterSpec(String curveName) { Provider[] providers = Security.getProviders(); GeneralSecurityException ex = null; // scan through the providers to see if anyone supports this for (Provider provider : providers) { try { KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("EC", provider); keyPairGenerator.initialize(new ECGenParameterSpec(curveName)); ECPublicKey publicKey = (ECPublicKey) keyPairGenerator.generateKeyPair().getPublic(); return publicKey.getParams(); } catch (GeneralSecurityException e) { ex = e; } } boolean bcProvider = Security.getProvider("BC") != null || Security.getProvider("BCFIPS") != null; throw new KubernetesClientException("Cannot determine EC parameter spec for curve name/OID" + (bcProvider ? "" : ". A BouncyCastle provider is not installed, it may be needed for this EC algorithm."), ex); } private static String oidToString(byte[] oid) { StringBuilder result = new StringBuilder(); int value = oid[0] & 0xff; result.append(value / 40).append(".").append(value % 40); for (int index = 1; index < oid.length; ++index) { byte bValue = oid[index]; if (bValue < 0) { value = (bValue & 0b01111111); ++index; if (index == oid.length) { throw new IllegalArgumentException("Invalid OID"); } value <<= 7; value |= (oid[index] & 0b01111111); result.append(".").append(value); } else { result.append(".").append(bValue); } } return result.toString(); } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy