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 */ CertId(X509Certificate issuerCert, SerialNumber serialNumber)72 public CertId(X509Certificate issuerCert, SerialNumber serialNumber) 73 throws IOException { 74 75 this(issuerCert.getSubjectX500Principal(), 76 issuerCert.getPublicKey(), serialNumber); 77 } 78 CertId(X500Principal issuerName, PublicKey issuerKey, SerialNumber serialNumber)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 */ CertId(DerInputStream derIn)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 */ getHashAlgorithm()128 public AlgorithmId getHashAlgorithm() { 129 return hashAlgId; 130 } 131 132 /** 133 * Return the hash value for the issuer name. 134 */ getIssuerNameHash()135 public byte[] getIssuerNameHash() { 136 return issuerNameHash; 137 } 138 139 /** 140 * Return the hash value for the issuer key. 141 */ getIssuerKeyHash()142 public byte[] getIssuerKeyHash() { 143 return issuerKeyHash; 144 } 145 146 /** 147 * Return the serial number. 148 */ getSerialNumber()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 */ encode(DerOutputStream out)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 */ hashCode()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 */ equals(Object other)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 */ toString()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