Home | History | Annotate | Download | only in certpath
      1 /*
      2  * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
      3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
      4  *
      5  * This code is free software; you can redistribute it and/or modify it
      6  * under the terms of the GNU General Public License version 2 only, as
      7  * published by the Free Software Foundation.  Oracle designates this
      8  * particular file as subject to the "Classpath" exception as provided
      9  * by Oracle in the LICENSE file that accompanied this code.
     10  *
     11  * This code is distributed in the hope that it will be useful, but WITHOUT
     12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
     13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
     14  * version 2 for more details (a copy is included in the LICENSE file that
     15  * accompanied this code).
     16  *
     17  * You should have received a copy of the GNU General Public License version
     18  * 2 along with this work; if not, write to the Free Software Foundation,
     19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
     20  *
     21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
     22  * or visit www.oracle.com if you need additional information or have any
     23  * questions.
     24  */
     25 
     26 package sun.security.provider.certpath;
     27 
     28 import java.io.IOException;
     29 import java.math.BigInteger;
     30 import java.security.MessageDigest;
     31 import java.security.NoSuchAlgorithmException;
     32 import java.security.PublicKey;
     33 import java.security.cert.X509Certificate;
     34 import java.util.Arrays;
     35 import javax.security.auth.x500.X500Principal;
     36 import sun.misc.HexDumpEncoder;
     37 import sun.security.x509.*;
     38 import sun.security.util.*;
     39 
     40 /**
     41  * This class corresponds to the CertId field in OCSP Request
     42  * and the OCSP Response. The ASN.1 definition for CertID is defined
     43  * in RFC 2560 as:
     44  * <pre>
     45  *
     46  * CertID          ::=     SEQUENCE {
     47  *      hashAlgorithm       AlgorithmIdentifier,
     48  *      issuerNameHash      OCTET STRING, -- Hash of Issuer's DN
     49  *      issuerKeyHash       OCTET STRING, -- Hash of Issuers public key
     50  *      serialNumber        CertificateSerialNumber
     51  *      }
     52  *
     53  * </pre>
     54  *
     55  * @author      Ram Marti
     56  */
     57 
     58 public class CertId {
     59 
     60     private static final boolean debug = false;
     61     private static final AlgorithmId SHA1_ALGID
     62         = new AlgorithmId(AlgorithmId.SHA_oid);
     63     private final AlgorithmId hashAlgId;
     64     private final byte[] issuerNameHash;
     65     private final byte[] issuerKeyHash;
     66     private final SerialNumber certSerialNumber;
     67     private int myhash = -1; // hashcode for this CertId
     68 
     69     /**
     70      * Creates a CertId. The hash algorithm used is SHA-1.
     71      */
     72     public CertId(X509Certificate issuerCert, SerialNumber serialNumber)
     73         throws IOException {
     74 
     75         this(issuerCert.getSubjectX500Principal(),
     76              issuerCert.getPublicKey(), serialNumber);
     77     }
     78 
     79     public CertId(X500Principal issuerName, PublicKey issuerKey,
     80                   SerialNumber serialNumber) throws IOException {
     81 
     82         // compute issuerNameHash
     83         MessageDigest md = null;
     84         try {
     85             md = MessageDigest.getInstance("SHA1");
     86         } catch (NoSuchAlgorithmException nsae) {
     87             throw new IOException("Unable to create CertId", nsae);
     88         }
     89         hashAlgId = SHA1_ALGID;
     90         md.update(issuerName.getEncoded());
     91         issuerNameHash = md.digest();
     92 
     93         // compute issuerKeyHash (remove the tag and length)
     94         byte[] pubKey = issuerKey.getEncoded();
     95         DerValue val = new DerValue(pubKey);
     96         DerValue[] seq = new DerValue[2];
     97         seq[0] = val.data.getDerValue(); // AlgorithmID
     98         seq[1] = val.data.getDerValue(); // Key
     99         byte[] keyBytes = seq[1].getBitString();
    100         md.update(keyBytes);
    101         issuerKeyHash = md.digest();
    102         certSerialNumber = serialNumber;
    103 
    104         if (debug) {
    105             HexDumpEncoder encoder = new HexDumpEncoder();
    106             System.out.println("Issuer Name is " + issuerName);
    107             System.out.println("issuerNameHash is " +
    108                 encoder.encodeBuffer(issuerNameHash));
    109             System.out.println("issuerKeyHash is " +
    110                 encoder.encodeBuffer(issuerKeyHash));
    111             System.out.println("SerialNumber is " + serialNumber.getNumber());
    112         }
    113     }
    114 
    115     /**
    116      * Creates a CertId from its ASN.1 DER encoding.
    117      */
    118     public CertId(DerInputStream derIn) throws IOException {
    119         hashAlgId = AlgorithmId.parse(derIn.getDerValue());
    120         issuerNameHash = derIn.getOctetString();
    121         issuerKeyHash = derIn.getOctetString();
    122         certSerialNumber = new SerialNumber(derIn);
    123     }
    124 
    125     /**
    126      * Return the hash algorithm identifier.
    127      */
    128     public AlgorithmId getHashAlgorithm() {
    129         return hashAlgId;
    130     }
    131 
    132     /**
    133      * Return the hash value for the issuer name.
    134      */
    135     public byte[] getIssuerNameHash() {
    136         return issuerNameHash;
    137     }
    138 
    139     /**
    140      * Return the hash value for the issuer key.
    141      */
    142     public byte[] getIssuerKeyHash() {
    143         return issuerKeyHash;
    144     }
    145 
    146     /**
    147      * Return the serial number.
    148      */
    149     public BigInteger getSerialNumber() {
    150         return certSerialNumber.getNumber();
    151     }
    152 
    153     /**
    154      * Encode the CertId using ASN.1 DER.
    155      * The hash algorithm used is SHA-1.
    156      */
    157     public void encode(DerOutputStream out) throws IOException {
    158 
    159         DerOutputStream tmp = new DerOutputStream();
    160         hashAlgId.encode(tmp);
    161         tmp.putOctetString(issuerNameHash);
    162         tmp.putOctetString(issuerKeyHash);
    163         certSerialNumber.encode(tmp);
    164         out.write(DerValue.tag_Sequence, tmp);
    165 
    166         if (debug) {
    167             HexDumpEncoder encoder = new HexDumpEncoder();
    168             System.out.println("Encoded certId is " +
    169                 encoder.encode(out.toByteArray()));
    170         }
    171     }
    172 
    173    /**
    174      * Returns a hashcode value for this CertId.
    175      *
    176      * @return the hashcode value.
    177      */
    178     @Override public int hashCode() {
    179         if (myhash == -1) {
    180             myhash = hashAlgId.hashCode();
    181             for (int i = 0; i < issuerNameHash.length; i++) {
    182                 myhash += issuerNameHash[i] * i;
    183             }
    184             for (int i = 0; i < issuerKeyHash.length; i++) {
    185                 myhash += issuerKeyHash[i] * i;
    186             }
    187             myhash += certSerialNumber.getNumber().hashCode();
    188         }
    189         return myhash;
    190     }
    191 
    192     /**
    193      * Compares this CertId for equality with the specified
    194      * object. Two CertId objects are considered equal if their hash algorithms,
    195      * their issuer name and issuer key hash values and their serial numbers
    196      * are equal.
    197      *
    198      * @param other the object to test for equality with this object.
    199      * @return true if the objects are considered equal, false otherwise.
    200      */
    201     @Override public boolean equals(Object other) {
    202         if (this == other) {
    203             return true;
    204         }
    205         if (other == null || (!(other instanceof CertId))) {
    206             return false;
    207         }
    208 
    209         CertId that = (CertId) other;
    210         if (hashAlgId.equals(that.getHashAlgorithm()) &&
    211             Arrays.equals(issuerNameHash, that.getIssuerNameHash()) &&
    212             Arrays.equals(issuerKeyHash, that.getIssuerKeyHash()) &&
    213             certSerialNumber.getNumber().equals(that.getSerialNumber())) {
    214             return true;
    215         } else {
    216             return false;
    217         }
    218     }
    219 
    220     /**
    221      * Create a string representation of the CertId.
    222      */
    223     @Override public String toString() {
    224         StringBuilder sb = new StringBuilder();
    225         sb.append("CertId \n");
    226         sb.append("Algorithm: " + hashAlgId.toString() +"\n");
    227         sb.append("issuerNameHash \n");
    228         HexDumpEncoder encoder = new HexDumpEncoder();
    229         sb.append(encoder.encode(issuerNameHash));
    230         sb.append("\nissuerKeyHash: \n");
    231         sb.append(encoder.encode(issuerKeyHash));
    232         sb.append("\n" +  certSerialNumber.toString());
    233         return sb.toString();
    234     }
    235 }
    236