1 13 14 package org.ejbca.core.protocol; 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.GeneralSecurityException ; 21 import java.security.InvalidKeyException ; 22 import java.security.NoSuchAlgorithmException ; 23 import java.security.NoSuchProviderException ; 24 import java.security.PrivateKey ; 25 import java.security.PublicKey ; 26 import java.security.cert.CertificateException ; 27 import java.security.cert.X509Certificate ; 28 import java.util.Collection ; 29 import java.util.Enumeration ; 30 import java.util.Iterator ; 31 32 import org.apache.log4j.Logger; 33 import org.bouncycastle.asn1.ASN1InputStream; 34 import org.bouncycastle.asn1.ASN1OctetString; 35 import org.bouncycastle.asn1.ASN1Sequence; 36 import org.bouncycastle.asn1.ASN1Set; 37 import org.bouncycastle.asn1.DEREncodable; 38 import org.bouncycastle.asn1.DERObject; 39 import org.bouncycastle.asn1.DEROctetString; 40 import org.bouncycastle.asn1.DEROutputStream; 41 import org.bouncycastle.asn1.DERPrintableString; 42 import org.bouncycastle.asn1.cms.Attribute; 43 import org.bouncycastle.asn1.cms.CMSObjectIdentifiers; 44 import org.bouncycastle.asn1.cms.ContentInfo; 45 import org.bouncycastle.asn1.cms.EnvelopedData; 46 import org.bouncycastle.asn1.cms.IssuerAndSerialNumber; 47 import org.bouncycastle.asn1.cms.KeyTransRecipientInfo; 48 import org.bouncycastle.asn1.cms.RecipientIdentifier; 49 import org.bouncycastle.asn1.cms.RecipientInfo; 50 import org.bouncycastle.asn1.cms.SignedData; 51 import org.bouncycastle.asn1.cms.SignerInfo; 52 import org.bouncycastle.cms.CMSEnvelopedData; 53 import org.bouncycastle.cms.CMSException; 54 import org.bouncycastle.cms.CMSSignedData; 55 import org.bouncycastle.cms.CMSSignedGenerator; 56 import org.bouncycastle.cms.RecipientInformation; 57 import org.bouncycastle.cms.RecipientInformationStore; 58 import org.bouncycastle.cms.SignerInformation; 59 import org.bouncycastle.cms.SignerInformationStore; 60 import org.bouncycastle.jce.PKCS10CertificationRequest; 61 import org.ejbca.util.Base64; 62 import org.ejbca.util.CertTools; 63 64 65 71 public class ScepRequestMessage extends PKCS10RequestMessage implements IRequestMessage { 72 81 static final long serialVersionUID = -235623330828902051L; 82 83 private static Logger log = Logger.getLogger(ScepRequestMessage.class); 84 85 public static final String id_Verisign = "2.16.840.1.113733"; 86 public static final String id_pki = id_Verisign + ".1"; 87 public static final String id_attributes = id_pki + ".9"; 88 public static final String id_messageType = id_attributes + ".2"; 89 public static final String id_pkiStatus = id_attributes + ".3"; 90 public static final String id_failInfo = id_attributes + ".4"; 91 public static final String id_senderNonce = id_attributes + ".5"; 92 public static final String id_recipientNonce = id_attributes + ".6"; 93 public static final String id_transId = id_attributes + ".7"; 94 public static final String id_extensionReq = id_attributes + ".8"; 95 96 97 private byte[] scepmsg; 98 99 109 private int messageType = 0; 110 public static int SCEP_TYPE_PKCSREQ = 19; 111 public static int SCEP_TYPE_GETCERTINITIAL = 20; public static int SCEP_TYPE_GETCRL = 22; 113 public static int SCEP_TYPE_GETCERT = 21; 114 115 119 private String senderNonce = null; 120 121 122 private String transactionId = null; 123 124 125 private byte[] requestKeyInfo = null; 126 127 128 private int error = 0; 129 130 131 private String errorText = null; 132 133 135 private transient String issuerDN = null; 136 137 139 private transient BigInteger serialNo = null; 140 141 142 private transient SignedData sd = null; 143 144 145 private transient EnvelopedData envData = null; 146 147 148 private transient ContentInfo envEncData = null; 149 150 151 private transient PrivateKey privateKey = null; 152 153 private transient String jceProvider = "BC"; 154 155 156 private transient IssuerAndSerialNumber issuerAndSerno = null; 157 158 159 private transient String preferredDigestAlg = CMSSignedGenerator.DIGEST_MD5; 160 161 private transient X509Certificate signercert; 162 163 171 public ScepRequestMessage(byte[] msg, boolean incCACert) throws IOException { 172 log.debug(">ScepRequestMessage"); 173 this.scepmsg = msg; 174 this.includeCACert = incCACert; 175 init(); 176 log.debug("<ScepRequestMessage"); 177 } 178 179 private void init() throws IOException { 180 log.debug(">init"); 181 182 try { 183 CMSSignedData csd = new CMSSignedData(scepmsg); 184 SignerInformationStore infoStore = csd.getSignerInfos(); 185 Collection signers = infoStore.getSigners(); 186 Iterator iter = signers.iterator(); 187 if (iter.hasNext()) { 188 SignerInformation si = (SignerInformation)iter.next(); 189 preferredDigestAlg = si.getDigestAlgOID(); 190 log.debug("Set "+ preferredDigestAlg+" as preferred digest algorithm for SCEP"); 191 } 192 } catch (CMSException e) { 193 log.error("CMSException trying to get preferred digest algorithm: ", e); 195 } 196 198 ASN1Sequence seq = (ASN1Sequence) new ASN1InputStream(new ByteArrayInputStream (scepmsg)).readObject(); 199 ContentInfo ci = new ContentInfo(seq); 200 String ctoid = ci.getContentType().getId(); 201 202 if (ctoid.equals(CMSObjectIdentifiers.signedData.getId())) { 203 sd = new SignedData((ASN1Sequence) ci.getContent()); 208 209 ASN1Set certs = sd.getCertificates(); 211 if (certs.size() > 0) { 212 DEREncodable dercert = certs.getObjectAt(0); 214 if (dercert != null) { 215 ByteArrayOutputStream bOut = new ByteArrayOutputStream (); 217 DEROutputStream dOut = new DEROutputStream(bOut); 218 dOut.writeObject(dercert); 219 if (bOut.size() > 0) { 220 requestKeyInfo = bOut.toByteArray(); 221 try { 223 signercert = CertTools.getCertfromByteArray(requestKeyInfo); 224 log.debug("requestKeyInfo is SubjectDN: " + signercert.getSubjectDN().toString() + 225 ", Serial=" + signercert.getSerialNumber().toString(16) + 226 "; IssuerDN: "+ signercert.getIssuerDN().toString()); 227 } catch (CertificateException e) { 228 log.error("Error parsing requestKeyInfo : ", e); 229 } 230 231 } 232 } 233 } 234 235 Enumeration sis = sd.getSignerInfos().getObjects(); 236 237 if (sis.hasMoreElements()) { 238 SignerInfo si = new SignerInfo((ASN1Sequence) sis.nextElement()); 239 Enumeration attr = si.getAuthenticatedAttributes().getObjects(); 240 241 while (attr.hasMoreElements()) { 242 Attribute a = new Attribute((ASN1Sequence) attr.nextElement()); 243 244 log.debug("Found attribute: " + a.getAttrType().getId()); 245 246 if (a.getAttrType().getId().equals(id_senderNonce)) { 247 Enumeration values = a.getAttrValues().getObjects(); 248 ASN1OctetString str = ASN1OctetString.getInstance(values.nextElement()); 249 senderNonce = new String (Base64.encode(str.getOctets(), false)); 250 log.debug("senderNonce = " + senderNonce); 251 } 252 if (a.getAttrType().getId().equals(id_transId)) { 253 Enumeration values = a.getAttrValues().getObjects(); 254 DERPrintableString str = DERPrintableString.getInstance(values.nextElement()); 255 transactionId = str.getString(); 256 log.debug("transactionId = " + transactionId); 257 } 258 if (a.getAttrType().getId().equals(id_messageType)) { 259 Enumeration values = a.getAttrValues().getObjects(); 260 DERPrintableString str = DERPrintableString.getInstance(values.nextElement()); 261 messageType = Integer.parseInt(str.getString()); 262 log.debug("messagetype = " + messageType); 263 } 264 } 265 } 266 267 if ((messageType == ScepRequestMessage.SCEP_TYPE_PKCSREQ) || (messageType == ScepRequestMessage.SCEP_TYPE_GETCRL) || (messageType == ScepRequestMessage.SCEP_TYPE_GETCERTINITIAL)) { 269 ci = sd.getEncapContentInfo(); 273 ctoid = ci.getContentType().getId(); 274 275 if (ctoid.equals(CMSObjectIdentifiers.data.getId())) { 276 DEROctetString content = (DEROctetString) ci.getContent(); 277 log.debug("envelopedData is " + content.getOctets().length + " bytes."); 278 279 ASN1Sequence seq1 = (ASN1Sequence) new ASN1InputStream(new ByteArrayInputStream (content.getOctets())).readObject(); 280 envEncData = new ContentInfo(seq1); 281 ctoid = envEncData.getContentType().getId(); 282 283 if (ctoid.equals(CMSObjectIdentifiers.envelopedData.getId())) { 284 envData = new EnvelopedData((ASN1Sequence) envEncData.getContent()); 285 ASN1Set recipientInfos = envData.getRecipientInfos(); 286 Enumeration e = recipientInfos.getObjects(); 287 while (e.hasMoreElements()) { 288 RecipientInfo ri = RecipientInfo.getInstance(e.nextElement()); 289 KeyTransRecipientInfo recipientInfo = KeyTransRecipientInfo.getInstance(ri.getInfo()); 290 RecipientIdentifier rid = recipientInfo.getRecipientIdentifier(); 291 IssuerAndSerialNumber iasn = IssuerAndSerialNumber.getInstance(rid.getId()); 292 issuerDN = iasn.getName().toString(); 293 serialNo = iasn.getSerialNumber().getValue(); 294 log.debug("IssuerDN: " + issuerDN); 295 log.debug("SerialNumber: " + iasn.getSerialNumber().getValue().toString(16)); 296 } 297 } else { 298 errorText = "EncapsulatedContentInfo does not contain PKCS7 envelopedData: "; 299 log.error(errorText + ctoid); 300 error = 2; 301 } 302 } else { 303 errorText = "EncapsulatedContentInfo is not of type 'data': "; 304 log.error(errorText + ctoid); 305 error = 3; 306 } 307 } else { 308 errorText = "This is not a certification request!"; 309 log.error(errorText); 310 error = 4; 311 } 312 } else { 313 errorText = "PKCSReq does not contain 'signedData': "; 314 log.error(errorText + ctoid); 315 error = 1; 316 } 317 318 log.debug("<init"); 319 } 321 private void decrypt() throws CMSException, NoSuchProviderException , GeneralSecurityException , IOException { 322 log.debug(">decrypt"); 323 324 if (privateKey == null) { 327 errorText = "Need private key to decrypt!"; 328 error = 5; 329 log.error(errorText); 330 return; 331 } 332 333 if (envEncData == null) { 334 errorText = "No enveloped data to decrypt!"; 335 error = 6; 336 log.error(errorText); 337 return; 338 } 339 340 CMSEnvelopedData ed = new CMSEnvelopedData(envEncData); 341 RecipientInformationStore recipients = ed.getRecipientInfos(); 342 Collection c = recipients.getRecipients(); 343 Iterator it = c.iterator(); 344 byte[] decBytes = null; 345 346 while (it.hasNext()) { 347 RecipientInformation recipient = (RecipientInformation) it.next(); 348 log.debug("Privatekey : " + privateKey.getAlgorithm()); 349 decBytes = recipient.getContent(privateKey, jceProvider); 350 break; 351 } 352 353 DERObject derobj = new ASN1InputStream(new ByteArrayInputStream (decBytes)).readObject(); 354 if (messageType == ScepRequestMessage.SCEP_TYPE_PKCSREQ) { 355 ASN1Sequence seq = (ASN1Sequence) derobj; 356 pkcs10 = new PKCS10CertificationRequest(seq); 357 log.debug("Successfully extracted PKCS10."); 358 } 360 if (messageType == ScepRequestMessage.SCEP_TYPE_GETCRL) { 361 issuerAndSerno = IssuerAndSerialNumber.getInstance(derobj); 362 log.debug("Successfully extracted IssuerAndSerialNumber."); 363 } 364 log.debug("<decrypt"); 365 } 367 372 public PublicKey getRequestPublicKey() { 373 log.debug(">getRequestPublicKey()"); 374 PublicKey ret = null; 375 try { 376 if (envData == null) { 377 init(); 378 decrypt(); 379 } 380 ret = super.getRequestPublicKey(); 381 } catch (IOException e) { 382 log.error("PKCS7 not inited!"); 383 } catch (GeneralSecurityException e) { 384 log.error("Error in PKCS7:", e); 385 } catch (CMSException e) { 386 log.error("Error in PKCS7:", e); 387 } 388 log.debug("<getRequestPublicKey()"); 389 return ret; 390 } 391 392 403 public boolean verify() { 404 log.debug(">verify()"); 405 boolean ret = false; 406 try { 407 if (pkcs10 == null) { 408 init(); 409 decrypt(); 410 } 411 ret = super.verify(); 412 } catch (IOException e) { 413 log.error("PKCS7 not inited!"); 414 } catch (GeneralSecurityException e) { 415 log.error("Error in PKCS7:", e); 416 } catch (CMSException e) { 417 log.error("Error in PKCS7:", e); 418 } 419 log.debug("<verify()"); 420 return ret; 421 } 422 423 428 public String getPassword() { 429 log.debug(">getPassword()"); 430 String ret = null; 431 try { 432 if (pkcs10 == null) { 433 init(); 434 decrypt(); 435 } 436 ret = super.getPassword(); 437 } catch (IOException e) { 438 log.error("PKCS7 not inited!"); 439 } catch (GeneralSecurityException e) { 440 log.error("Error in PKCS7:", e); 441 } catch (CMSException e) { 442 log.error("Error in PKCS7:", e); 443 } 444 log.debug("<getPassword()"); 445 return ret; 446 } 447 448 454 public String getUsername() { 455 log.debug(">getUsername()"); 456 String ret = null; 457 try { 458 if (pkcs10 == null) { 459 init(); 460 decrypt(); 461 } 462 ret = super.getUsername(); 463 if (ret == null) { 464 String name = CertTools.getPartFromDN(getRequestDN(), "SN"); 466 if (name == null) { 467 log.error("No SN in DN: "+getRequestDN()); 468 return null; 469 } 470 int index = name.indexOf(' '); 474 ret = name; 475 if (index > 0) { 476 ret = name.substring(0,index); 477 } else { 478 index = name.indexOf('+'); 480 if (index > 0) { 481 ret = name.substring(0, index); 482 } 483 } 484 } 485 } catch (IOException e) { 486 log.error("PKCS7 not inited!"); 487 } catch (GeneralSecurityException e) { 488 log.error("Error in PKCS7:", e); 489 } catch (CMSException e) { 490 log.error("Error in PKCS7:", e); 491 } 492 log.debug("<getUsername(): " + ret); 493 return ret; 494 } 495 496 501 public String getIssuerDN() { 502 log.debug(">getIssuerDN()"); 503 String ret = null; 504 try { 505 if (envData == null) { 506 init(); 507 } 508 ret = issuerDN; 509 } catch (IOException e) { 510 log.error("PKCS7 not inited!"); 511 } 512 log.debug("<getIssuerDN(): " + ret); 513 return ret; 514 } 515 516 521 public BigInteger getSerialNo() { 522 log.debug(">getSerialNo()"); 523 getIssuerDN(); 525 return serialNo; 526 } 527 528 533 public String getCRLIssuerDN() { 534 log.debug(">getCRLIssuerDN()"); 535 String ret = null; 536 try { 537 if (issuerAndSerno == null) { 538 init(); 539 decrypt(); 540 } 541 ret = CertTools.stringToBCDNString(issuerAndSerno.getName().toString()); 542 } catch (IOException e) { 543 log.error("PKCS7 not inited!"); 544 } catch (GeneralSecurityException e) { 545 log.error("Error in PKCS7:", e); 546 } catch (CMSException e) { 547 log.error("Error in PKCS7:", e); 548 } 549 log.debug("<getCRLIssuerDN(): " + ret); 550 return ret; 551 } 552 553 558 public BigInteger getCRLSerialNo() { 559 log.debug(">getCRLSerialNo()"); 560 BigInteger ret = null; 561 try { 562 if (issuerAndSerno == null) { 563 init(); 564 decrypt(); 565 } 566 ret = issuerAndSerno.getSerialNumber().getValue(); 567 } catch (IOException e) { 568 log.error("PKCS7 not inited!"); 569 } catch (GeneralSecurityException e) { 570 log.error("Error in PKCS7:", e); 571 } catch (CMSException e) { 572 log.error("Error in PKCS7:", e); 573 } 574 log.debug("<getCRLSerialNo(): " + ret); 575 return ret; 576 } 577 578 583 public String getRequestDN() { 584 log.debug(">getRequestDN()"); 585 String ret = null; 586 try { 587 if (pkcs10 == null) { 588 init(); 589 decrypt(); 590 } 591 ret = super.getRequestDN(); 592 } catch (IOException e) { 593 log.error("PKCS7 not inited!"); 594 } catch (GeneralSecurityException e) { 595 log.error("Error in PKCS7:", e); 596 } catch (CMSException e) { 597 log.error("Error in PKCS7:", e); 598 } 599 log.debug("<getRequestDN(): " + ret); 600 return ret; 601 } 602 603 609 public boolean requireKeyInfo() { 610 return true; 611 } 612 613 623 public void setKeyInfo(X509Certificate cert, PrivateKey key, String provider) { 624 this.privateKey = key; 627 if (provider == null) { 628 this.jceProvider = "BC"; 629 } else { 630 this.jceProvider = provider; 631 } 632 } 633 634 639 public int getErrorNo() { 640 return error; 641 } 642 643 648 public String getErrorText() { 649 return errorText; 650 } 651 652 657 public String getSenderNonce() { 658 return senderNonce; 659 } 660 661 666 public String getTransactionId() { 667 return transactionId; 668 } 669 670 675 public byte[] getRequestKeyInfo() { 676 return requestKeyInfo; 677 } 678 679 683 public int getMessageType() { 684 return messageType; 685 686 } 687 688 690 public String getPreferredDigestAlg() { 691 return preferredDigestAlg; 692 } 693 694 699 public X509Certificate getSignerCert(){ 700 return signercert; 701 } 702 703 704 727 728 } | Popular Tags |