1 13 14 package org.ejbca.core.protocol.cmp; 15 16 import java.io.ByteArrayInputStream ; 17 import java.io.ByteArrayOutputStream ; 18 import java.io.IOException ; 19 import java.math.BigInteger ; 20 import java.security.InvalidKeyException ; 21 import java.security.KeyFactory ; 22 import java.security.NoSuchAlgorithmException ; 23 import java.security.NoSuchProviderException ; 24 import java.security.PrivateKey ; 25 import java.security.PublicKey ; 26 import java.security.Signature ; 27 import java.security.SignatureException ; 28 import java.security.cert.Certificate ; 29 import java.security.cert.X509Certificate ; 30 import java.security.spec.X509EncodedKeySpec ; 31 import java.util.Date ; 32 33 import org.apache.commons.lang.StringUtils; 34 import org.apache.log4j.Logger; 35 import org.bouncycastle.asn1.ASN1InputStream; 36 import org.bouncycastle.asn1.ASN1OctetString; 37 import org.bouncycastle.asn1.DERBitString; 38 import org.bouncycastle.asn1.DEREncodable; 39 import org.bouncycastle.asn1.DERObject; 40 import org.bouncycastle.asn1.DEROctetString; 41 import org.bouncycastle.asn1.DEROutputStream; 42 import org.bouncycastle.asn1.DERUTF8String; 43 import org.bouncycastle.asn1.x509.AlgorithmIdentifier; 44 import org.bouncycastle.asn1.x509.GeneralName; 45 import org.bouncycastle.asn1.x509.GeneralNames; 46 import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo; 47 import org.bouncycastle.asn1.x509.Time; 48 import org.bouncycastle.asn1.x509.X509Extension; 49 import org.bouncycastle.asn1.x509.X509Extensions; 50 import org.bouncycastle.asn1.x509.X509Name; 51 import org.bouncycastle.cms.CMSSignedGenerator; 52 import org.ejbca.core.protocol.IRequestMessage; 53 import org.ejbca.core.protocol.IResponseMessage; 54 import org.ejbca.core.protocol.RequestMessageUtils; 55 import org.ejbca.util.Base64; 56 import org.ejbca.util.CertTools; 57 58 import com.novosec.pkix.asn1.cmp.PKIBody; 59 import com.novosec.pkix.asn1.cmp.PKIHeader; 60 import com.novosec.pkix.asn1.cmp.PKIMessage; 61 import com.novosec.pkix.asn1.crmf.AttributeTypeAndValue; 62 import com.novosec.pkix.asn1.crmf.CRMFObjectIdentifiers; 63 import com.novosec.pkix.asn1.crmf.CertReqMessages; 64 import com.novosec.pkix.asn1.crmf.CertReqMsg; 65 import com.novosec.pkix.asn1.crmf.CertRequest; 66 import com.novosec.pkix.asn1.crmf.CertTemplate; 67 import com.novosec.pkix.asn1.crmf.OptionalValidity; 68 import com.novosec.pkix.asn1.crmf.POPOSigningKey; 69 import com.novosec.pkix.asn1.crmf.ProofOfPossession; 70 71 80 public class CrmfRequestMessage extends BaseCmpMessage implements IRequestMessage { 81 82 private static final Logger log = Logger.getLogger(CrmfRequestMessage.class); 83 84 93 static final long serialVersionUID = 1001L; 94 95 private int requestType = 0; 96 private int requestId = 0; 97 private PKIMessage msg; 98 private CertReqMsg req; 99 private String b64SenderNonce = null; 100 private String b64TransId = null; 101 private String defaultCA = null; 102 private boolean allowRaVerifyPopo = false; 103 private String extractUsernameComponent = null; 104 105 private String username = null; 106 107 private String password = null; 108 109 110 private transient String preferredDigestAlg = CMSSignedGenerator.DIGEST_SHA1; 111 112 120 public CrmfRequestMessage(PKIMessage msg, String defaultCA, boolean allowRaVerifyPopo, String extractUsernameComponent) { 121 this.msg = msg; 122 PKIBody body = msg.getBody(); 123 PKIHeader header = msg.getHeader(); 124 requestType = body.getTagNo(); 125 CertReqMessages msgs = getCertReqFromTag(body, requestType); 126 requestId = msgs.getCertReqMsg(0).getCertReq().getCertReqId().getValue().intValue(); 127 this.defaultCA = defaultCA; 128 this.allowRaVerifyPopo = allowRaVerifyPopo; 129 this.extractUsernameComponent = extractUsernameComponent; 130 this.req = msgs.getCertReqMsg(0); 131 setMessage(this.msg); 132 DEROctetString os = header.getTransactionID(); 133 if (os != null) { 134 byte[] val = os.getOctets(); 135 if (val != null) { 136 setTransactionId(new String (Base64.encode(val))); 137 } 138 } 139 os = header.getSenderNonce(); 140 if (os != null) { 141 byte[] val = os.getOctets(); 142 if (val != null) { 143 setSenderNonce(new String (Base64.encode(val))); 144 } 145 } 146 setRecipient(header.getRecipient()); 147 setSender(header.getSender()); 148 } 149 150 public PublicKey getRequestPublicKey() throws InvalidKeyException , NoSuchAlgorithmException , NoSuchProviderException { 151 CertRequest request = req.getCertReq(); 152 CertTemplate templ = request.getCertTemplate(); 153 SubjectPublicKeyInfo keyInfo = templ.getPublicKey(); 154 PublicKey pk = getPublicKey(keyInfo, "BC"); 155 return pk; 156 } 157 private PublicKey getPublicKey(SubjectPublicKeyInfo subjectPKInfo, String provider) throws NoSuchAlgorithmException , NoSuchProviderException , InvalidKeyException { 158 try { 159 X509EncodedKeySpec xspec = new X509EncodedKeySpec (new DERBitString(subjectPKInfo).getBytes()); 160 AlgorithmIdentifier keyAlg = subjectPKInfo.getAlgorithmId (); 161 return KeyFactory.getInstance(keyAlg.getObjectId().getId (), provider).generatePublic(xspec); 162 } catch (java.security.spec.InvalidKeySpecException e) { 163 InvalidKeyException newe = new InvalidKeyException ("Error decoding public key."); 164 newe.initCause(e); 165 throw newe; 166 } 167 } 168 169 171 public void setPassword(String pwd) { 172 this.password = pwd; 173 } 174 public String getPassword() { 175 String ret = null; 176 if (password != null) { 177 log.debug("Returning a pre-set password in CRMF request"); 178 ret = password; 179 } else { 180 AttributeTypeAndValue av = null; 182 int i = 0; 183 do { 184 av = req.getRegInfo(i); 185 if (av != null) { 186 if (StringUtils.equals(CRMFObjectIdentifiers.regCtrl_regToken.getId(), av.getObjectId().getId())) { 187 DEREncodable enc = av.getParameters(); 188 DERUTF8String str = DERUTF8String.getInstance(enc); 189 ret = str.getString(); 190 log.debug("Found a request password in CRMF request regCtrl_regToken"); 191 } 192 } 193 i++; 194 } while ( (av != null) && (ret == null) ); 195 } 196 if (ret == null) { 197 } 200 return ret; 201 } 202 203 205 public void setUsername(String username) { 206 this.username = username; 207 } 208 209 public String getUsername() { 210 String ret = null; 211 if (username != null) { 212 ret = username; 213 } else { 214 String component = extractUsernameComponent; 216 if (StringUtils.isEmpty(component)) { 217 component = "CN"; 218 } 219 String name = CertTools.getPartFromDN(getRequestDN(), component); 220 if (name == null) { 221 log.error("No component "+component+" in DN: "+getRequestDN()); 222 } else { 223 ret = name; 224 } 225 } 226 log.debug("Username is: "+ret); 227 return ret; 228 } 229 230 public void setIssuerDN(String issuer) { 231 this.defaultCA = issuer; 232 } 233 public String getIssuerDN() { 234 String ret = null; 235 CertTemplate templ = req.getCertReq().getCertTemplate(); 236 X509Name name = templ.getIssuer(); 237 if (name != null) { 238 ret = CertTools.stringToBCDNString(name.toString()); 239 } else { 240 ret = defaultCA; 241 } 242 log.debug("Issuer DN is: "+ret); 243 return ret; 244 } 245 246 public BigInteger getSerialNo() { 247 return null; 248 } 249 250 public String getCRLIssuerDN() { 251 return null; 252 } 253 254 public BigInteger getCRLSerialNo() { 255 return null; 256 } 257 258 public String getRequestDN() { 259 String ret = null; 260 CertTemplate templ = req.getCertReq().getCertTemplate(); 261 X509Name name = templ.getSubject(); 262 if (name != null) { 263 ret = CertTools.stringToBCDNString(name.toString()); 264 } 265 log.debug("Request DN is: "+ret); 266 return ret; 267 } 268 269 public String getRequestAltNames() { 270 String ret = null; 271 CertTemplate templ = req.getCertReq().getCertTemplate(); 272 X509Extensions exts = templ.getExtensions(); 273 if (exts != null) { 274 X509Extension ext = exts.getExtension(X509Extensions.SubjectAlternativeName); 275 if (ext != null) { 276 ASN1OctetString octs = ext.getValue(); 278 if (octs != null) { 279 ASN1InputStream aIn = new ASN1InputStream(new ByteArrayInputStream (octs.getOctets())); 280 DERObject obj; 281 try { 282 obj = aIn.readObject(); 283 GeneralNames gan = GeneralNames.getInstance(obj); 284 GeneralName[] gns = gan.getNames(); 285 String altName = null; 286 for (int i = 0; i < gns.length; i++) { 287 GeneralName gn = gns[i]; 288 int tag = gn.getTagNo(); 289 DEREncodable name = gn.getName(); 290 String str = CertTools.getGeneralNameString(tag, name); 291 if (altName == null) { 292 altName = str; 293 } else { 294 altName += ", "+str; 295 } 296 } 297 ret = altName; 298 } catch (IOException e) { 299 log.error("IOExceptioon parsing altNames: ", e); 300 return null; 301 } 302 } 303 } 304 } 305 log.debug("Request altName is: "+ret); 306 return ret; 307 } 308 309 310 public Date getRequestValidityNotBefore() { 311 Date ret = null; 312 CertTemplate templ = req.getCertReq().getCertTemplate(); 313 OptionalValidity val = templ.getValidity(); 314 if (val != null) { 315 Time time = val.getNotBefore(); 316 if (time != null) { 317 ret = time.getDate(); 318 } 319 } 320 log.debug("Request validity notBefore is: "+(ret == null ? "null" : ret.toString())); 321 return ret; 322 } 323 324 public Date getRequestValidityNotAfter() { 325 Date ret = null; 326 CertTemplate templ = req.getCertReq().getCertTemplate(); 327 OptionalValidity val = templ.getValidity(); 328 if (val != null) { 329 Time time = val.getNotAfter(); 330 if (time != null) { 331 ret = time.getDate(); 332 } 333 } 334 log.debug("Request validity notAfter is: "+(ret == null ? "null" : ret.toString())); 335 return ret; 336 } 337 338 public boolean verify() throws InvalidKeyException , NoSuchAlgorithmException , NoSuchProviderException { 339 boolean ret = false; 340 ProofOfPossession pop = req.getPop(); 341 if ( (pop.getRaVerified() != null) && allowRaVerifyPopo) { 342 ret = true; 343 } else if (pop.getSignature() != null) { 344 try { 345 POPOSigningKey sk = pop.getSignature(); 346 AlgorithmIdentifier algId = sk.getAlgorithmIdentifier(); 347 log.debug("POP algorithm identifier is: "+algId.getObjectId().getId()); 348 DERBitString bs = sk.getSignature(); 349 PublicKey pk = getRequestPublicKey(); 350 ByteArrayOutputStream bao = new ByteArrayOutputStream (); 351 DEROutputStream out = new DEROutputStream(bao); 352 out.writeObject(req.getCertReq()); 353 byte[] protBytes = bao.toByteArray(); 354 log.debug("POP protection bytes length: "+protBytes.length); 355 Signature sig; 356 sig = Signature.getInstance(algId.getObjectId().getId(), "BC"); 357 sig.initVerify(pk); 358 sig.update(protBytes); 359 ret = sig.verify(bs.getBytes()); 360 } catch (IOException e) { 361 log.error("Error encoding CertReqMsg: ", e); 362 } catch (SignatureException e) { 363 log.error("SignatureException verifying POP: ", e); 364 } 365 } 366 return ret; 367 } 368 369 public boolean requireKeyInfo() { 370 return false; 371 } 372 373 public void setKeyInfo(X509Certificate cert, PrivateKey key, String provider) { 374 } 375 376 public int getErrorNo() { 377 return 0; 378 } 379 380 public String getErrorText() { 381 return null; 382 } 383 384 public void setSenderNonce(String b64nonce) { 385 this.b64SenderNonce = b64nonce; 386 } 387 public String getSenderNonce() { 388 return b64SenderNonce; 389 } 390 391 public void setTransactionId(String b64transid) { 392 this.b64TransId = b64transid; 393 } 394 public String getTransactionId() { 395 return b64TransId; 396 } 397 398 public byte[] getRequestKeyInfo() { 399 return null; 400 } 401 402 public String getPreferredDigestAlg() { 403 return preferredDigestAlg; 404 } 405 406 public boolean includeCACert() { 407 return false; 408 } 409 410 412 public int getRequestType() { 413 return requestType; 414 } 415 416 418 public int getRequestId() { 419 return requestId; 420 } 421 422 public String getSubjectDN() { 424 String ret = null; 425 CertTemplate templ = req.getCertReq().getCertTemplate(); 426 X509Name name = templ.getSubject(); 427 if (name != null) { 428 ret = CertTools.stringToBCDNString(name.toString()); 429 } 430 return ret; 431 } 432 433 private CertReqMessages getCertReqFromTag(PKIBody body, int tag) { 434 CertReqMessages msgs = null; 435 switch (tag) { 436 case 0: 437 msgs = body.getIr(); 438 break; 439 case 2: 440 msgs = body.getCr(); 441 break; 442 case 7: 443 msgs = body.getKur(); 444 break; 445 case 9: 446 msgs = body.getKrr(); 447 break; 448 case 13: 449 msgs = body.getCcr(); 450 break; 451 default: 452 break; 453 } 454 return msgs; 455 } 456 458 public IResponseMessage createResponseMessage(Class responseClass, IRequestMessage req, Certificate cert, PrivateKey signPriv, PrivateKey encPriv, String provider) { 459 return RequestMessageUtils.createResponseMessage(responseClass, req, cert, signPriv, encPriv, provider); 460 } 461 } 462 | Popular Tags |