1 /* 2 * Licensed to the Apache Software Foundation (ASF) under one or more 3 * contributor license agreements. See the NOTICE file distributed with 4 * this work for additional information regarding copyright ownership. 5 * The ASF licenses this file to You under the Apache License, Version 2.0 6 * (the "License"); you may not use this file except in compliance with 7 * the License. You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17 18 /** 19 * @author Alexander Y. Kleymenov 20 * @version $Revision$ 21 */ 22 23 package org.apache.harmony.security.x509; 24 25 import java.security.KeyFactory; 26 import java.security.NoSuchAlgorithmException; 27 import java.security.PublicKey; 28 import java.security.spec.InvalidKeySpecException; 29 import java.security.spec.KeySpec; 30 import java.security.spec.X509EncodedKeySpec; 31 import org.apache.harmony.security.asn1.ASN1BitString; 32 import org.apache.harmony.security.asn1.ASN1Sequence; 33 import org.apache.harmony.security.asn1.ASN1Type; 34 import org.apache.harmony.security.asn1.BerInputStream; 35 import org.apache.harmony.security.asn1.BitString; 36 37 /** 38 * The class encapsulates the ASN.1 DER encoding/decoding work 39 * with the following structure which is a part of X.509 certificate 40 * (as specified in RFC 3280 - 41 * Internet X.509 Public Key Infrastructure. 42 * Certificate and Certificate Revocation List (CRL) Profile. 43 * http://www.ietf.org/rfc/rfc3280.txt): 44 * 45 * <pre> 46 * SubjectPublicKeyInfo ::= SEQUENCE { 47 * algorithm AlgorithmIdentifier, 48 * subjectPublicKey BIT STRING 49 * } 50 * </pre> 51 */ 52 public final class SubjectPublicKeyInfo { 53 /** the value of algorithmID field of the structure */ 54 private AlgorithmIdentifier algorithmID; 55 /** the value of subjectPublicKey field of the structure */ 56 private byte[] subjectPublicKey; 57 /** the public key corresponding to this SubjectPublicKeyInfo */ 58 private PublicKey publicKey; 59 /** the value of unusedBits field of the structure */ 60 private int unusedBits; 61 /** the ASN.1 encoded form of SubjectPublicKeyInfo */ 62 private byte[] encoding; 63 64 public SubjectPublicKeyInfo(AlgorithmIdentifier algID, byte[] subjectPublicKey) { 65 this(algID, subjectPublicKey, 0); 66 } 67 68 public SubjectPublicKeyInfo(AlgorithmIdentifier algID, byte[] subjectPublicKey, int unused) { 69 this(algID, subjectPublicKey, 0, null); 70 } 71 72 private SubjectPublicKeyInfo(AlgorithmIdentifier algID, 73 byte[] subjectPublicKey, int unused, 74 byte[] encoding) { 75 this.algorithmID = algID; 76 this.subjectPublicKey = subjectPublicKey; 77 this.unusedBits = unused; 78 this.encoding = encoding; 79 } 80 81 /** 82 * Returns the value of algorithmIdentifier field of the structure. 83 */ 84 public AlgorithmIdentifier getAlgorithmIdentifier() { 85 return algorithmID; 86 } 87 88 /** 89 * Returns the value of subjectPublicKey field of the structure. 90 */ 91 public byte[] getSubjectPublicKey() { 92 return subjectPublicKey; 93 } 94 95 /** 96 * Returns ASN.1 encoded form of this X.509 SubjectPublicKeyInfo value. 97 */ 98 public byte[] getEncoded() { 99 if (encoding == null) { 100 encoding = ASN1.encode(this); 101 } 102 return encoding; 103 } 104 105 /** 106 * Returns the PublicKey corresponding to this SubjectPublicKeyInfo 107 * instance. 108 */ 109 public PublicKey getPublicKey() { 110 if (publicKey == null) { 111 final byte[] encoded = getEncoded(); 112 final KeySpec keySpec = new X509EncodedKeySpec(encoded); 113 114 /* Try using the algorithm name first. */ 115 final String algName = algorithmID.getAlgorithmName(); 116 publicKey = generateKeyForAlgorithm(keySpec, algName); 117 118 /* 119 * Fall back to using the algorithm OID if it's not the same as the 120 * algorithm name. 121 */ 122 final String algOid = algorithmID.getAlgorithm(); 123 if (publicKey == null && !algOid.equals(algName)) { 124 publicKey = generateKeyForAlgorithm(keySpec, algOid); 125 } 126 127 /* 128 * Encode this as an X.509 public key since we didn't have any 129 * KeyFactory that could handle this algorithm name or OID. Perhaps 130 * the thing that's using this can decode it. 131 */ 132 if (publicKey == null) { 133 publicKey = new X509PublicKey(algOid, encoded, subjectPublicKey); 134 } 135 } 136 return publicKey; 137 } 138 139 /** 140 * Try to generate a PublicKey for a given {@code keySpec} and 141 * {@code algorithm} identifier. If there a problem generating the key like 142 * a missing {@code KeyFactory} or invalid {@code KeySpec}, it will return 143 * {@code null}. 144 */ 145 private static PublicKey generateKeyForAlgorithm(KeySpec keySpec, String algorithm) { 146 try { 147 return KeyFactory.getInstance(algorithm).generatePublic(keySpec); 148 } catch (InvalidKeySpecException ignored) { 149 } catch (NoSuchAlgorithmException ignored) { 150 } 151 return null; 152 } 153 154 public static final ASN1Sequence ASN1 = new ASN1Sequence(new ASN1Type[] { 155 AlgorithmIdentifier.ASN1, ASN1BitString.getInstance() }) { 156 @Override protected Object getDecodedObject(BerInputStream in) { 157 Object[] values = (Object[]) in.content; 158 return new SubjectPublicKeyInfo( 159 (AlgorithmIdentifier) values[0], 160 ((BitString) values[1]).bytes, 161 ((BitString) values[1]).unusedBits, 162 in.getEncoded()); 163 } 164 165 @Override protected void getValues(Object object, Object[] values) { 166 SubjectPublicKeyInfo spki = (SubjectPublicKeyInfo) object; 167 values[0] = spki.algorithmID; 168 values[1] = new BitString(spki.subjectPublicKey, spki.unusedBits); 169 } 170 }; 171 } 172 173