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.ASN1EncodableVector; 19 import org.bouncycastle.asn1.ASN1Encoding; 20 import org.bouncycastle.asn1.ASN1InputStream; 21 import org.bouncycastle.asn1.ASN1Object; 22 import org.bouncycastle.asn1.ASN1Primitive; 23 import org.bouncycastle.asn1.ASN1Sequence; 24 import org.bouncycastle.asn1.DERBitString; 25 import org.bouncycastle.asn1.DERIA5String; 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 ASN1Object 47 { 48 AlgorithmIdentifier sigAlg; 49 AlgorithmIdentifier keyAlg; 50 byte sigBits []; 51 String challenge; 52 DERBitString content; 53 PublicKey pubkey ; 54 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 64 public NetscapeCertRequest( 65 byte[] req) 66 throws IOException 67 { 68 this(getReq(req)); 69 } 70 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 = AlgorithmIdentifier.getInstance(spkac.getObjectAt(1)); 90 sigBits = ((DERBitString)spkac.getObjectAt(2)).getOctets(); 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 = SubjectPublicKeyInfo.getInstance(pkac.getObjectAt(0)); 113 114 X509EncodedKeySpec xspec = new X509EncodedKeySpec(new DERBitString( 115 pubkeyinfo).getBytes()); 116 117 keyAlg = pubkeyinfo.getAlgorithm(); 118 pubkey = KeyFactory.getInstance(keyAlg.getAlgorithm().getId(), "BC") 119 .generatePublic(xspec); 120 121 } 122 catch (Exception e) 123 { 124 throw new IllegalArgumentException(e.toString()); 125 } 126 } 127 128 public NetscapeCertRequest( 129 String challenge, 130 AlgorithmIdentifier signing_alg, 131 PublicKey pub_key) throws NoSuchAlgorithmException, 132 InvalidKeySpecException, NoSuchProviderException 133 { 134 135 this.challenge = challenge; 136 sigAlg = signing_alg; 137 pubkey = pub_key; 138 139 ASN1EncodableVector content_der = new ASN1EncodableVector(); 140 content_der.add(getKeySpec()); 141 //content_der.add(new SubjectPublicKeyInfo(sigAlg, new RSAPublicKeyStructure(pubkey.getModulus(), pubkey.getPublicExponent()).getDERObject())); 142 content_der.add(new DERIA5String(challenge)); 143 144 try 145 { 146 content = new DERBitString(new DERSequence(content_der)); 147 } 148 catch (IOException e) 149 { 150 throw new InvalidKeySpecException("exception encoding key: " + e.toString()); 151 } 152 } 153 154 public String getChallenge() 155 { 156 return challenge; 157 } 158 159 public void setChallenge(String value) 160 { 161 challenge = value; 162 } 163 164 public AlgorithmIdentifier getSigningAlgorithm() 165 { 166 return sigAlg; 167 } 168 169 public void setSigningAlgorithm(AlgorithmIdentifier value) 170 { 171 sigAlg = value; 172 } 173 174 public AlgorithmIdentifier getKeyAlgorithm() 175 { 176 return keyAlg; 177 } 178 179 public void setKeyAlgorithm(AlgorithmIdentifier value) 180 { 181 keyAlg = value; 182 } 183 184 public PublicKey getPublicKey() 185 { 186 return pubkey; 187 } 188 189 public void setPublicKey(PublicKey value) 190 { 191 pubkey = value; 192 } 193 194 public boolean verify(String challenge) throws NoSuchAlgorithmException, 195 InvalidKeyException, SignatureException, NoSuchProviderException 196 { 197 if (!challenge.equals(this.challenge)) 198 { 199 return false; 200 } 201 202 // 203 // Verify the signature .. shows the response was generated 204 // by someone who knew the associated private key 205 // 206 Signature sig = Signature.getInstance(sigAlg.getAlgorithm().getId(), 207 "BC"); 208 sig.initVerify(pubkey); 209 sig.update(content.getBytes()); 210 211 return sig.verify(sigBits); 212 } 213 214 public void sign(PrivateKey priv_key) throws NoSuchAlgorithmException, 215 InvalidKeyException, SignatureException, NoSuchProviderException, 216 InvalidKeySpecException 217 { 218 sign(priv_key, null); 219 } 220 221 public void sign(PrivateKey priv_key, SecureRandom rand) 222 throws NoSuchAlgorithmException, InvalidKeyException, 223 SignatureException, NoSuchProviderException, 224 InvalidKeySpecException 225 { 226 Signature sig = Signature.getInstance(sigAlg.getAlgorithm().getId(), 227 "BC"); 228 229 if (rand != null) 230 { 231 sig.initSign(priv_key, rand); 232 } 233 else 234 { 235 sig.initSign(priv_key); 236 } 237 238 ASN1EncodableVector pkac = new ASN1EncodableVector(); 239 240 pkac.add(getKeySpec()); 241 pkac.add(new DERIA5String(challenge)); 242 243 try 244 { 245 sig.update(new DERSequence(pkac).getEncoded(ASN1Encoding.DER)); 246 } 247 catch (IOException ioe) 248 { 249 throw new SignatureException(ioe.getMessage()); 250 } 251 252 sigBits = sig.sign(); 253 } 254 255 private ASN1Primitive getKeySpec() throws NoSuchAlgorithmException, 256 InvalidKeySpecException, NoSuchProviderException 257 { 258 ByteArrayOutputStream baos = new ByteArrayOutputStream(); 259 260 ASN1Primitive obj = null; 261 try 262 { 263 264 baos.write(pubkey.getEncoded()); 265 baos.close(); 266 267 ASN1InputStream derin = new ASN1InputStream( 268 new ByteArrayInputStream(baos.toByteArray())); 269 270 obj = derin.readObject(); 271 } 272 catch (IOException ioe) 273 { 274 throw new InvalidKeySpecException(ioe.getMessage()); 275 } 276 return obj; 277 } 278 279 public ASN1Primitive toASN1Primitive() 280 { 281 ASN1EncodableVector spkac = new ASN1EncodableVector(); 282 ASN1EncodableVector pkac = new ASN1EncodableVector(); 283 284 try 285 { 286 pkac.add(getKeySpec()); 287 } 288 catch (Exception e) 289 { 290 //ignore 291 } 292 293 pkac.add(new DERIA5String(challenge)); 294 295 spkac.add(new DERSequence(pkac)); 296 spkac.add(sigAlg); 297 spkac.add(new DERBitString(sigBits)); 298 299 return new DERSequence(spkac); 300 } 301 } 302