Home | History | Annotate | Download | only in x509
      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