1package org.bouncycastle.jce.netscape; 2 3import java.io.ByteArrayInputStream; 4import java.io.ByteArrayOutputStream; 5import java.io.IOException; 6import java.security.InvalidKeyException; 7import java.security.KeyFactory; 8import java.security.NoSuchAlgorithmException; 9import java.security.NoSuchProviderException; 10import java.security.PrivateKey; 11import java.security.PublicKey; 12import java.security.SecureRandom; 13import java.security.Signature; 14import java.security.SignatureException; 15import java.security.spec.InvalidKeySpecException; 16import java.security.spec.X509EncodedKeySpec; 17 18import org.bouncycastle.asn1.ASN1EncodableVector; 19import org.bouncycastle.asn1.ASN1Encoding; 20import org.bouncycastle.asn1.ASN1InputStream; 21import org.bouncycastle.asn1.ASN1Object; 22import org.bouncycastle.asn1.ASN1Primitive; 23import org.bouncycastle.asn1.ASN1Sequence; 24import org.bouncycastle.asn1.DERBitString; 25import org.bouncycastle.asn1.DERIA5String; 26import org.bouncycastle.asn1.DERSequence; 27import org.bouncycastle.asn1.x509.AlgorithmIdentifier; 28import 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 **/ 45public 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 = 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 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 try 147 { 148 content = new DERBitString(new DERSequence(content_der)); 149 } 150 catch (IOException e) 151 { 152 throw new InvalidKeySpecException("exception encoding key: " + e.toString()); 153 } 154 } 155 156 public String getChallenge() 157 { 158 return challenge; 159 } 160 161 public void setChallenge(String value) 162 { 163 challenge = value; 164 } 165 166 public AlgorithmIdentifier getSigningAlgorithm() 167 { 168 return sigAlg; 169 } 170 171 public void setSigningAlgorithm(AlgorithmIdentifier value) 172 { 173 sigAlg = value; 174 } 175 176 public AlgorithmIdentifier getKeyAlgorithm() 177 { 178 return keyAlg; 179 } 180 181 public void setKeyAlgorithm(AlgorithmIdentifier value) 182 { 183 keyAlg = value; 184 } 185 186 public PublicKey getPublicKey() 187 { 188 return pubkey; 189 } 190 191 public void setPublicKey(PublicKey value) 192 { 193 pubkey = value; 194 } 195 196 public boolean verify(String challenge) throws NoSuchAlgorithmException, 197 InvalidKeyException, SignatureException, NoSuchProviderException 198 { 199 if (!challenge.equals(this.challenge)) 200 { 201 return false; 202 } 203 204 // 205 // Verify the signature .. shows the response was generated 206 // by someone who knew the associated private key 207 // 208 Signature sig = Signature.getInstance(sigAlg.getObjectId().getId(), 209 "BC"); 210 sig.initVerify(pubkey); 211 sig.update(content.getBytes()); 212 213 return sig.verify(sigBits); 214 } 215 216 public void sign(PrivateKey priv_key) throws NoSuchAlgorithmException, 217 InvalidKeyException, SignatureException, NoSuchProviderException, 218 InvalidKeySpecException 219 { 220 sign(priv_key, null); 221 } 222 223 public void sign(PrivateKey priv_key, SecureRandom rand) 224 throws NoSuchAlgorithmException, InvalidKeyException, 225 SignatureException, NoSuchProviderException, 226 InvalidKeySpecException 227 { 228 Signature sig = Signature.getInstance(sigAlg.getAlgorithm().getId(), 229 "BC"); 230 231 if (rand != null) 232 { 233 sig.initSign(priv_key, rand); 234 } 235 else 236 { 237 sig.initSign(priv_key); 238 } 239 240 ASN1EncodableVector pkac = new ASN1EncodableVector(); 241 242 pkac.add(getKeySpec()); 243 pkac.add(new DERIA5String(challenge)); 244 245 try 246 { 247 sig.update(new DERSequence(pkac).getEncoded(ASN1Encoding.DER)); 248 } 249 catch (IOException ioe) 250 { 251 throw new SignatureException(ioe.getMessage()); 252 } 253 254 sigBits = sig.sign(); 255 } 256 257 private ASN1Primitive getKeySpec() throws NoSuchAlgorithmException, 258 InvalidKeySpecException, NoSuchProviderException 259 { 260 ByteArrayOutputStream baos = new ByteArrayOutputStream(); 261 262 ASN1Primitive obj = null; 263 try 264 { 265 266 baos.write(pubkey.getEncoded()); 267 baos.close(); 268 269 ASN1InputStream derin = new ASN1InputStream( 270 new ByteArrayInputStream(baos.toByteArray())); 271 272 obj = derin.readObject(); 273 } 274 catch (IOException ioe) 275 { 276 throw new InvalidKeySpecException(ioe.getMessage()); 277 } 278 return obj; 279 } 280 281 public ASN1Primitive toASN1Primitive() 282 { 283 ASN1EncodableVector spkac = new ASN1EncodableVector(); 284 ASN1EncodableVector pkac = new ASN1EncodableVector(); 285 286 try 287 { 288 pkac.add(getKeySpec()); 289 } 290 catch (Exception e) 291 { 292 //ignore 293 } 294 295 pkac.add(new DERIA5String(challenge)); 296 297 spkac.add(new DERSequence(pkac)); 298 spkac.add(sigAlg); 299 spkac.add(new DERBitString(sigBits)); 300 301 return new DERSequence(spkac); 302 } 303} 304