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