1 package org.bouncycastle.jce.netscape; 2 3 import java.io.ByteArrayInputStream; 4 import java.io.ByteArrayOutputStream; 5 import java.io.IOException; 6 import java.security.InvalidKeyException; 7 import java.security.KeyFactory; 8 import java.security.NoSuchAlgorithmException; 9 import java.security.NoSuchProviderException; 10 import java.security.PrivateKey; 11 import java.security.PublicKey; 12 import java.security.SecureRandom; 13 import java.security.Signature; 14 import java.security.SignatureException; 15 import java.security.spec.InvalidKeySpecException; 16 import java.security.spec.X509EncodedKeySpec; 17 18 import org.bouncycastle.asn1.ASN1Encodable; 19 import org.bouncycastle.asn1.ASN1EncodableVector; 20 import org.bouncycastle.asn1.ASN1InputStream; 21 import org.bouncycastle.asn1.ASN1Sequence; 22 import org.bouncycastle.asn1.DERBitString; 23 import org.bouncycastle.asn1.DERIA5String; 24 import org.bouncycastle.asn1.DERObject; 25 import org.bouncycastle.asn1.DERSequence; 26 import org.bouncycastle.asn1.x509.AlgorithmIdentifier; 27 import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo; 28 29 /** 30 * 31 * 32 * Handles NetScape certificate request (KEYGEN), these are constructed as: 33 * <pre><code> 34 * SignedPublicKeyAndChallenge ::= SEQUENCE { 35 * publicKeyAndChallenge PublicKeyAndChallenge, 36 * signatureAlgorithm AlgorithmIdentifier, 37 * signature BIT STRING 38 * } 39 * </pre> 40 * 41 * PublicKey's encoded-format has to be X.509. 42 * 43 **/ 44 public class NetscapeCertRequest 45 extends ASN1Encodable 46 { 47 AlgorithmIdentifier sigAlg; 48 AlgorithmIdentifier keyAlg; 49 byte sigBits []; 50 String challenge; 51 DERBitString content; 52 PublicKey pubkey ; 53 getReq( byte[] r)54 private static ASN1Sequence getReq( 55 byte[] r) 56 throws IOException 57 { 58 ASN1InputStream aIn = new ASN1InputStream(new ByteArrayInputStream(r)); 59 60 return ASN1Sequence.getInstance(aIn.readObject()); 61 } 62 NetscapeCertRequest( byte[] req)63 public NetscapeCertRequest( 64 byte[] req) 65 throws IOException 66 { 67 this(getReq(req)); 68 } 69 NetscapeCertRequest(ASN1Sequence spkac)70 public NetscapeCertRequest (ASN1Sequence spkac) 71 { 72 try 73 { 74 75 // 76 // SignedPublicKeyAndChallenge ::= SEQUENCE { 77 // publicKeyAndChallenge PublicKeyAndChallenge, 78 // signatureAlgorithm AlgorithmIdentifier, 79 // signature BIT STRING 80 // } 81 // 82 if (spkac.size() != 3) 83 { 84 throw new IllegalArgumentException("invalid SPKAC (size):" 85 + spkac.size()); 86 } 87 88 sigAlg = new AlgorithmIdentifier((ASN1Sequence)spkac 89 .getObjectAt(1)); 90 sigBits = ((DERBitString)spkac.getObjectAt(2)).getBytes(); 91 92 // 93 // PublicKeyAndChallenge ::= SEQUENCE { 94 // spki SubjectPublicKeyInfo, 95 // challenge IA5STRING 96 // } 97 // 98 ASN1Sequence pkac = (ASN1Sequence)spkac.getObjectAt(0); 99 100 if (pkac.size() != 2) 101 { 102 throw new IllegalArgumentException("invalid PKAC (len): " 103 + pkac.size()); 104 } 105 106 challenge = ((DERIA5String)pkac.getObjectAt(1)).getString(); 107 108 //this could be dangerous, as ASN.1 decoding/encoding 109 //could potentially alter the bytes 110 content = new DERBitString(pkac); 111 112 SubjectPublicKeyInfo pubkeyinfo = new SubjectPublicKeyInfo( 113 (ASN1Sequence)pkac.getObjectAt(0)); 114 115 X509EncodedKeySpec xspec = new X509EncodedKeySpec(new DERBitString( 116 pubkeyinfo).getBytes()); 117 118 keyAlg = pubkeyinfo.getAlgorithmId(); 119 pubkey = KeyFactory.getInstance(keyAlg.getObjectId().getId(), "BC") 120 .generatePublic(xspec); 121 122 } 123 catch (Exception e) 124 { 125 throw new IllegalArgumentException(e.toString()); 126 } 127 } 128 NetscapeCertRequest( String challenge, AlgorithmIdentifier signing_alg, PublicKey pub_key)129 public NetscapeCertRequest( 130 String challenge, 131 AlgorithmIdentifier signing_alg, 132 PublicKey pub_key) throws NoSuchAlgorithmException, 133 InvalidKeySpecException, NoSuchProviderException 134 { 135 136 this.challenge = challenge; 137 sigAlg = signing_alg; 138 pubkey = pub_key; 139 140 ASN1EncodableVector content_der = new ASN1EncodableVector(); 141 content_der.add(getKeySpec()); 142 //content_der.add(new SubjectPublicKeyInfo(sigAlg, new RSAPublicKeyStructure(pubkey.getModulus(), pubkey.getPublicExponent()).getDERObject())); 143 content_der.add(new DERIA5String(challenge)); 144 145 content = new DERBitString(new DERSequence(content_der)); 146 } 147 getChallenge()148 public String getChallenge() 149 { 150 return challenge; 151 } 152 setChallenge(String value)153 public void setChallenge(String value) 154 { 155 challenge = value; 156 } 157 getSigningAlgorithm()158 public AlgorithmIdentifier getSigningAlgorithm() 159 { 160 return sigAlg; 161 } 162 setSigningAlgorithm(AlgorithmIdentifier value)163 public void setSigningAlgorithm(AlgorithmIdentifier value) 164 { 165 sigAlg = value; 166 } 167 getKeyAlgorithm()168 public AlgorithmIdentifier getKeyAlgorithm() 169 { 170 return keyAlg; 171 } 172 setKeyAlgorithm(AlgorithmIdentifier value)173 public void setKeyAlgorithm(AlgorithmIdentifier value) 174 { 175 keyAlg = value; 176 } 177 getPublicKey()178 public PublicKey getPublicKey() 179 { 180 return pubkey; 181 } 182 setPublicKey(PublicKey value)183 public void setPublicKey(PublicKey value) 184 { 185 pubkey = value; 186 } 187 verify(String challenge)188 public boolean verify(String challenge) throws NoSuchAlgorithmException, 189 InvalidKeyException, SignatureException, NoSuchProviderException 190 { 191 if (!challenge.equals(this.challenge)) 192 { 193 return false; 194 } 195 196 // 197 // Verify the signature .. shows the response was generated 198 // by someone who knew the associated private key 199 // 200 Signature sig = Signature.getInstance(sigAlg.getObjectId().getId(), 201 "BC"); 202 sig.initVerify(pubkey); 203 sig.update(content.getBytes()); 204 205 return sig.verify(sigBits); 206 } 207 sign(PrivateKey priv_key)208 public void sign(PrivateKey priv_key) throws NoSuchAlgorithmException, 209 InvalidKeyException, SignatureException, NoSuchProviderException, 210 InvalidKeySpecException 211 { 212 sign(priv_key, null); 213 } 214 sign(PrivateKey priv_key, SecureRandom rand)215 public void sign(PrivateKey priv_key, SecureRandom rand) 216 throws NoSuchAlgorithmException, InvalidKeyException, 217 SignatureException, NoSuchProviderException, 218 InvalidKeySpecException 219 { 220 Signature sig = Signature.getInstance(sigAlg.getObjectId().getId(), 221 "BC"); 222 223 if (rand != null) 224 { 225 sig.initSign(priv_key, rand); 226 } 227 else 228 { 229 sig.initSign(priv_key); 230 } 231 232 ASN1EncodableVector pkac = new ASN1EncodableVector(); 233 234 pkac.add(getKeySpec()); 235 pkac.add(new DERIA5String(challenge)); 236 237 try 238 { 239 sig.update(new DERSequence(pkac).getEncoded(ASN1Encodable.DER)); 240 } 241 catch (IOException ioe) 242 { 243 throw new SignatureException(ioe.getMessage()); 244 } 245 246 sigBits = sig.sign(); 247 } 248 getKeySpec()249 private DERObject getKeySpec() throws NoSuchAlgorithmException, 250 InvalidKeySpecException, NoSuchProviderException 251 { 252 ByteArrayOutputStream baos = new ByteArrayOutputStream(); 253 254 DERObject obj = null; 255 try 256 { 257 258 baos.write(pubkey.getEncoded()); 259 baos.close(); 260 261 ASN1InputStream derin = new ASN1InputStream( 262 new ByteArrayInputStream(baos.toByteArray())); 263 264 obj = derin.readObject(); 265 } 266 catch (IOException ioe) 267 { 268 throw new InvalidKeySpecException(ioe.getMessage()); 269 } 270 return obj; 271 } 272 toASN1Object()273 public DERObject toASN1Object() 274 { 275 ASN1EncodableVector spkac = new ASN1EncodableVector(); 276 ASN1EncodableVector pkac = new ASN1EncodableVector(); 277 278 try 279 { 280 pkac.add(getKeySpec()); 281 } 282 catch (Exception e) 283 { 284 //ignore 285 } 286 287 pkac.add(new DERIA5String(challenge)); 288 289 spkac.add(new DERSequence(pkac)); 290 spkac.add(sigAlg); 291 spkac.add(new DERBitString(sigBits)); 292 293 return new DERSequence(spkac); 294 } 295 } 296