Please review. thanks!
Christina
>From 23f532da661f2528c47df67c8663a0f4f96401ea Mon Sep 17 00:00:00 2001 From: Christina Fu <c...@redhat.com> Date: Thu, 13 Apr 2017 16:53:58 -0700 Subject: [PATCH] Ticket #2614 CMC: id-cmc-popLinkWitnessV2 feature implementation This patch provides the feature for CMC on handling id-cmc-popLinkWitnessV2 --- .../src/com/netscape/cmstools/CMCRequest.java | 445 +++++++++++++++++++-- .../src/com/netscape/cmstools/CRMFPopClient.java | 10 +- .../src/com/netscape/cmstools/PKCS10Client.java | 22 +- .../netscape/cms/profile/common/EnrollProfile.java | 416 ++++++++++++++----- .../cms/servlet/common/CMCOutputTemplate.java | 12 + base/server/cmsbundle/src/UserMessages.properties | 2 + 6 files changed, 752 insertions(+), 155 deletions(-) diff --git a/base/java-tools/src/com/netscape/cmstools/CMCRequest.java b/base/java-tools/src/com/netscape/cmstools/CMCRequest.java index a2aca8a..004b81d 100644 --- a/base/java-tools/src/com/netscape/cmstools/CMCRequest.java +++ b/base/java-tools/src/com/netscape/cmstools/CMCRequest.java @@ -34,6 +34,7 @@ import java.security.NoSuchAlgorithmException; import java.text.SimpleDateFormat; import java.util.Arrays; import java.util.Date; +import java.util.Random; import java.util.StringTokenizer; import org.mozilla.jss.CryptoManager; @@ -53,10 +54,12 @@ import org.mozilla.jss.crypto.CryptoToken; import org.mozilla.jss.crypto.DigestAlgorithm; import org.mozilla.jss.crypto.ObjectNotFoundException; import org.mozilla.jss.crypto.PrivateKey; +import org.mozilla.jss.crypto.Signature; import org.mozilla.jss.crypto.SignatureAlgorithm; import org.mozilla.jss.crypto.SymmetricKey; import org.mozilla.jss.crypto.X509Certificate; import org.mozilla.jss.pkcs10.CertificationRequest; +import org.mozilla.jss.pkcs10.CertificationRequestInfo; import org.mozilla.jss.pkix.cmc.CMCCertId; import org.mozilla.jss.pkix.cmc.CMCStatusInfo; import org.mozilla.jss.pkix.cmc.DecryptedPOP; @@ -68,6 +71,7 @@ import org.mozilla.jss.pkix.cmc.OtherInfo; import org.mozilla.jss.pkix.cmc.OtherMsg; import org.mozilla.jss.pkix.cmc.PKIData; import org.mozilla.jss.pkix.cmc.PendInfo; +import org.mozilla.jss.pkix.cmc.PopLinkWitnessV2; import org.mozilla.jss.pkix.cmc.ResponseBody; import org.mozilla.jss.pkix.cmc.TaggedAttribute; import org.mozilla.jss.pkix.cmc.TaggedCertificationRequest; @@ -85,7 +89,11 @@ import org.mozilla.jss.pkix.cms.SignerInfo; import org.mozilla.jss.pkix.crmf.CertReqMsg; import org.mozilla.jss.pkix.crmf.CertRequest; import org.mozilla.jss.pkix.crmf.CertTemplate; +import org.mozilla.jss.pkix.crmf.POPOSigningKey; +import org.mozilla.jss.pkix.crmf.ProofOfPossession; +import org.mozilla.jss.pkix.primitive.AVA; import org.mozilla.jss.pkix.primitive.AlgorithmIdentifier; +import org.mozilla.jss.pkix.primitive.Attribute; import org.mozilla.jss.pkix.primitive.Name; import org.mozilla.jss.pkix.primitive.SubjectPublicKeyInfo; import org.mozilla.jss.util.Password; @@ -148,6 +156,37 @@ public class CMCRequest { } /** + * getSigningAlgFromPrivate + * + */ + static SignatureAlgorithm getSigningAlgFromPrivate (java.security.PrivateKey privKey) { + String method = "getSigningAlgFromPrivate: "; + System.out.println(method + "begins."); + SignatureAlgorithm signAlg = null; + /* + org.mozilla.jss.crypto.PrivateKey.Type signingKeyType = + ((org.mozilla.jss.crypto.PrivateKey) privKey) + .getType(); + */ + // TODO: allow more options later + String signingKeyType = privKey.getAlgorithm(); + System.out.println(method + "found signingKeyType=" + signingKeyType); + if (signingKeyType.equalsIgnoreCase("RSA")) { + signAlg = SignatureAlgorithm.RSASignatureWithSHA256Digest; + } else if (signingKeyType.equalsIgnoreCase("EC")) { + signAlg = SignatureAlgorithm.ECSignatureWithSHA256Digest; + } else { + System.out.println(method + "Algorithm not supported:" + + signingKeyType); + return null; + } + System.out.println(method + "using SignatureAlgorithm: " + + signAlg.toString()); + + return signAlg; + } + + /** * signData signs the request PKIData * * @param signerCert the certificate of the authorized signer of the CMC revocation request. @@ -190,17 +229,9 @@ public class CMCRequest { EncapsulatedContentInfo ci = new EncapsulatedContentInfo(OBJECT_IDENTIFIER.id_cct_PKIData, pkidata); DigestAlgorithm digestAlg = null; - SignatureAlgorithm signAlg = null; - org.mozilla.jss.crypto.PrivateKey.Type signingKeyType = ((org.mozilla.jss.crypto.PrivateKey) privKey) - .getType(); - if (signingKeyType.equals(org.mozilla.jss.crypto.PrivateKey.Type.RSA)) { - signAlg = SignatureAlgorithm.RSASignatureWithSHA256Digest; - } else if (signingKeyType.equals(org.mozilla.jss.crypto.PrivateKey.Type.EC)) { - signAlg = SignatureAlgorithm.ECSignatureWithSHA256Digest; - } else { - System.out.println("Algorithm not supported"); + SignatureAlgorithm signAlg = getSigningAlgFromPrivate(privKey); + if (signAlg == null) return null; - } MessageDigest SHADigest = null; @@ -292,9 +323,13 @@ public class CMCRequest { String transactionMgtId, String identificationEnable, String identification, String identityProofEnable, String identityProofSharedSecret, - String identityProofV2Enable, String witnessSharedSecret, + String witnessSharedSecret, + String identityProofV2Enable, String identityProofV2hashAlg, String identityProofV2macAlg, - SEQUENCE controlSeq, SEQUENCE otherMsgSeq, int bpid) { + String popLinkWitnessV2Enable, + String popLinkWitnessV2keyGenAlg, String popLinkWitnessV2macAlg, + SEQUENCE controlSeq, SEQUENCE otherMsgSeq, int bpid, + CryptoToken token, PrivateKey privk) { String method = "createPKIData: "; @@ -305,6 +340,26 @@ public class CMCRequest { TaggedRequest trq = null; PKCS10 pkcs = null; CertReqMsg certReqMsg = null; + CertReqMsg new_certReqMsg = null; + CertRequest new_certreq = null; + + PopLinkWitnessV2 popLinkWitnessV2Control = null; + if (popLinkWitnessV2Enable.equals("true")) { + popLinkWitnessV2Control = + createPopLinkWitnessV2Attr( + bpid, + controlSeq, + witnessSharedSecret, + popLinkWitnessV2keyGenAlg, + popLinkWitnessV2macAlg, + (identificationEnable.equals("true")) ? + identification : null); + if (popLinkWitnessV2Control == null) { + System.out.println(method + + "createPopLinkWitnessV2Attr returned null...exit"); + System.exit(1); + } + } // create CMC req SEQUENCE reqSequence = new SEQUENCE(); @@ -325,9 +380,63 @@ public class CMCRequest { System.exit(1); } certReqMsg = (CertReqMsg) crmfMsgs.elementAt(0); - trq = new TaggedRequest(TaggedRequest.CRMF, null, - certReqMsg); + + if (popLinkWitnessV2Enable.equals("true")) { + System.out.println(method + + "popLinkWitnessV2 enabled. reconstructing crmf"); + //crmf reconstruction to include PopLinkWitnessV2 control + CertRequest certReq = certReqMsg.getCertReq(); + INTEGER certReqId = certReq.getCertReqId(); + CertTemplate certTemplate = certReq.getCertTemplate(); + SEQUENCE controls = certReq.getControls(); + controls.addElement(new AVA(OBJECT_IDENTIFIER.id_cmc_popLinkWitnessV2, + popLinkWitnessV2Control)); + new_certreq = new CertRequest(certReqId, certTemplate, controls); + + // recalculate signing POP, if it had one + ProofOfPossession new_pop = null; + if (certReqMsg.hasPop()) { + if (privk == null) { + System.out.println(method + + "privateKey not found; can't regenerate new POP"); + System.exit(1); + } + if (token == null) { + System.out.println(method + + "token not found; can't regenerate new POP"); + System.exit(1); + } + new_pop = createNewPOP( + certReqMsg, + new_certreq, + token, + privk); + } else { // !hasPop + System.out.println(method + + "old certReqMsg has no pop, so will the new certReqMsg"); + } + + new_certReqMsg = new CertReqMsg(new_certreq, new_pop, null); + SEQUENCE seq = new SEQUENCE(); + seq.addElement(new_certReqMsg); + + byte[] encodedNewCrmfMessage = ASN1Util.encode(seq); + String b64String = Utils.base64encode(encodedNewCrmfMessage); + System.out.println(method + "new CRMF b64encode completes."); + System.out.println(CryptoUtil.CERTREQ_BEGIN_HEADING); + System.out.println(b64String); + System.out.println(CryptoUtil.CERTREQ_END_HEADING); + System.out.println(""); + + trq = new TaggedRequest(TaggedRequest.CRMF, null, + new_certReqMsg); + + } else { // !popLinkWitnessV2Enable + trq = new TaggedRequest(TaggedRequest.CRMF, null, + certReqMsg); + } } else if (format.equals("pkcs10")) { + System.out.println(method + " format: pkcs10"); try { pkcs = new PKCS10(decodedBytes, true); } catch (Exception e2) { @@ -338,9 +447,82 @@ public class CMCRequest { pkcs.toByteArray()); CertificationRequest cr = (CertificationRequest) CertificationRequest.getTemplate() .decode(crInputStream); - TaggedCertificationRequest tcr = new TaggedCertificationRequest( - new INTEGER(bpid++), cr); - trq = new TaggedRequest(TaggedRequest.PKCS10, tcr, null); + if (popLinkWitnessV2Enable.equals("true")) { + System.out.println(method + + "popLinkWitnessV2 enabled. reconstructing pkcs#10"); + //pkcs#10 reconstruction to include PopLinkWitnessV2 control + + CertificationRequestInfo certReqInfo = cr.getInfo(); + + INTEGER version = certReqInfo.getVersion(); + Name subject = certReqInfo.getSubject(); + SubjectPublicKeyInfo spkInfo = certReqInfo.getSubjectPublicKeyInfo(); + /* + AlgorithmIdentifier alg = spkInfo.getAlgorithmIdentifier(); + SignatureAlgorithm signAlg = SignatureAlgorithm.fromOID(alg.getOID()); + if (signAlg == SignatureAlgorithm.RSASignatureWithSHA256Digest) { + System.out.println(method + + "signAlg == SignatureAlgorithm.RSASignatureWithSHA256Digest"); + } else { + System.out.println(method + + "signAlg == " + signAlg.toString()); + } + */ + + Attribute attr = new Attribute( + OBJECT_IDENTIFIER.id_cmc_popLinkWitnessV2, + popLinkWitnessV2Control); + SET attrs = certReqInfo.getAttributes(); + if (attrs == null) { + attrs = new SET(); + } + attrs.addElement(attr); + System.out.println(method + + " new pkcs#10 Attribute created for id_cmc_popLinkWitnessV2."); + + SignatureAlgorithm signAlg = getSigningAlgFromPrivate(privk); + if (signAlg == null) { + System.out.println(method + + "signAlg not found"); + System.exit(1); + } + CertificationRequestInfo new_certReqInfo = new CertificationRequestInfo( + version, + subject, + spkInfo, + attrs); + System.out.println(method + + " new pkcs#10 CertificationRequestInfo created."); + + CertificationRequest new_certRequest = new CertificationRequest( + new_certReqInfo, + privk, + signAlg); + System.out.println(method + + "new pkcs#10 CertificationRequest created."); + + ByteArrayOutputStream bos = new ByteArrayOutputStream(); + new_certRequest.encode(bos); + byte[] bb = bos.toByteArray(); + + System.out.println(method + "calling Utils.b64encode."); + String b64String = Utils.base64encode(bb); + System.out.println(method + "new PKCS#10 b64encode completes."); + System.out.println(CryptoUtil.CERTREQ_BEGIN_HEADING); + System.out.println(b64String); + System.out.println(CryptoUtil.CERTREQ_END_HEADING); + System.out.println(""); + + TaggedCertificationRequest tcr = new TaggedCertificationRequest( + new INTEGER(bpid++), new_certRequest); + trq = new TaggedRequest(TaggedRequest.PKCS10, tcr, null); + + } else { // !popLinkWitnessV2Enable + + TaggedCertificationRequest tcr = new TaggedCertificationRequest( + new INTEGER(bpid++), cr); + trq = new TaggedRequest(TaggedRequest.PKCS10, tcr, null); + } } else { System.out.println(method + " Unrecognized request format: " + format); System.exit(1); @@ -348,7 +530,7 @@ public class CMCRequest { reqSequence.addElement(trq); } } catch (Exception e) { - System.out.println(method + " Exception:" + e.toString()); + System.out.println(method + " Exception:" + e); System.exit(1); } @@ -380,6 +562,63 @@ public class CMCRequest { return pkidata; } + /** + * createNewPOP + * called in case of PopLinkwitnessV2 when pop exists, thus + * requiring recalculation due to changes in CertRequest controls + * + * @param old_certReqMsg, + * @param new_certReqMsg, + * @param token, + * @param privKey + * + * @author cfu + */ + static ProofOfPossession createNewPOP( + CertReqMsg old_certReqMsg, + CertRequest new_certReq, + CryptoToken token, + PrivateKey privKey) { + String method = "createNewPOP: "; + + System.out.println(method + "begins"); + if (old_certReqMsg == null || + new_certReq == null || + token == null || + privKey == null) { + System.out.println(method + "method params cannot be null."); + System.exit(1); + } + ProofOfPossession old_pop = old_certReqMsg.getPop(); + if (old_pop == null) { + System.out.println(method + "no pop in old_certReqMsg."); + System.exit(1); + } + + POPOSigningKey PopOfsignKey = old_pop.getSignature(); + AlgorithmIdentifier algId = PopOfsignKey.getAlgorithmIdentifier(); + + byte[] signature = null; + try { + SignatureAlgorithm signAlg = SignatureAlgorithm.fromOID(algId.getOID()); + Signature signer = token.getSignatureContext(signAlg); + signer.initSign(privKey); + ByteArrayOutputStream bo = new ByteArrayOutputStream(); + new_certReq.encode(bo); + signer.update(bo.toByteArray()); + signature = signer.sign(); + } catch (Exception e) { + System.out.println(method + e); + System.exit(1); + } + + System.out.println(method + "about to create POPOSigningKey"); + POPOSigningKey newPopOfSigningKey = new POPOSigningKey(null, algId, new BIT_STRING(signature, 0)); + + System.out.println(method + "creating and returning newPopOfSigningKey"); + return ProofOfPossession.createSignature(newPopOfSigningKey); + } + static void printUsage() { System.out.println(""); System.out.println("Usage: CMCRequest <configuration file>"); @@ -516,13 +755,29 @@ public class CMCRequest { System.out.println("identityProofV2.hashAlg=SHA-256"); System.out.println("identityProofV2.macAlg=SHA-256-HMAC"); System.out.println(""); + System.out.println("#witness.sharedSecret works with identityProofV2 and popLinkWitnessV2"); System.out.println("#witness.sharedSecret: Shared Secret"); System.out.println("witness.sharedSecret=testing"); System.out.println(""); - System.out.println("#identification works with identityProofV2"); + System.out.println("#identification works with identityProofV2 and popLinkWitnessV2"); System.out.println("identification.enable=false"); System.out.println("identification=testuser"); System.out.println(""); + System.out.println("#popLinkWitnessV2.enable: if true, then the underlying request will contain"); + System.out.println("#this control or attribute. Otherwise, false."); + System.out.println("#Supported keyGenAlg are:"); + System.out.println("# SHA-256, SHA-384, and SHA-512"); + System.out.println("#Supported macAlg are:"); + System.out.println("# SHA-256-HMAC, SHA-384-HMAC, and SHA-512-HMAC"); + System.out.println("popLinkWitnessV2.enable=false"); + System.out.println("popLinkWitnessV2.keyGenAlg=SHA-256"); + System.out.println("popLinkWitnessV2.macAlg=SHA-256-HMAC"); + System.out.println(""); + System.out.println(""); + System.out.println("###############################"); + System.out.println("Note: The following controls are outdated and replaced by newer"); + System.out.println(" controls above. They remain untouched, but also untested."); + System.out.println("###############################"); System.out.println("#identityProof.enable: if true, then the request will contain"); System.out.println("#this control. Otherwise, false."); System.out.println("#Note that this control is updated by identityProofV2 above"); @@ -879,7 +1134,7 @@ public class CMCRequest { System.out.println(""); seq.addElement(getCertControl); } catch (Exception e) { - System.out.println("Error in creating get certificate control. Check the parameters."); + System.out.println("Error in creating get certificate control. Check the parameters." + e); System.exit(1); } @@ -1023,6 +1278,111 @@ public class CMCRequest { return bpid; } + /** + * createPopLinkWitnessV2Attr generates witness v2 + * + * @param + * @return PopLinkWitnessV2 + * + * @author cfu + */ + private static PopLinkWitnessV2 createPopLinkWitnessV2Attr( + int bpid, SEQUENCE controlSeq, + String sharedSecret, + String keyGenAlgString, + String macAlgString, + String ident) { + + String method = "createPopLinkWitnessV2Attr: "; + byte[] key = null; + byte[] finalDigest = null; + + // (1) generate a random byte-string R of 512 bits + Random random = new Random(); + byte[] random_R = new byte[64]; + random.nextBytes(random_R); + + // default to SHA256 if not specified + if (keyGenAlgString == null) { + keyGenAlgString = "SHA-256"; + } + if (macAlgString == null) { + macAlgString = "SHA-256-HMAC"; + } + System.out.println(method + "keyGenAlg=" + keyGenAlgString + + "; macAlg=" + macAlgString); + + String toBeDigested = sharedSecret; + if (ident != null) { + toBeDigested = sharedSecret + ident; + } + + // (2) compute key from sharedSecret + identity + try { + MessageDigest hash = MessageDigest.getInstance(keyGenAlgString); + key = hash.digest(toBeDigested.getBytes()); + } catch (NoSuchAlgorithmException ex) { + System.out.println(method + "No such algorithm!"); + return null; + } + + MessageDigest mac; + // (3) compute MAC over R from (1) using key from (2) + try { + mac = MessageDigest.getInstance( + CryptoUtil.getHMACtoMessageDigestName(macAlgString)); + HMACDigest hmacDigest = new HMACDigest(mac, key); + hmacDigest.update(random_R); + finalDigest = hmacDigest.digest(); + } catch (NoSuchAlgorithmException ex) { + System.out.println(method + "No such algorithm!"); + return null; + } + + // (4) encode R as the value of a POP Link Random control + TaggedAttribute idPOPLinkRandom = + new TaggedAttribute(new INTEGER(bpid++), + OBJECT_IDENTIFIER.id_cmc_idPOPLinkRandom, + new OCTET_STRING(random_R)); + controlSeq.addElement(idPOPLinkRandom); + System.out.println(method + + "Successfully created id_cmc_idPOPLinkRandom control. bpid = " + + (bpid - 1)); + + AlgorithmIdentifier keyGenAlg; + try { + keyGenAlg = new AlgorithmIdentifier( + CryptoUtil.getHashAlgorithmOID(keyGenAlgString)); + } catch (NoSuchAlgorithmException ex) { + System.out.println(method + "No such hashing algorithm:" + keyGenAlgString); + return null; + } + AlgorithmIdentifier macAlg; + try { + macAlg = new AlgorithmIdentifier( + CryptoUtil.getHMACAlgorithmOID(macAlgString)); + } catch (NoSuchAlgorithmException ex) { + System.out.println(method + "No such HMAC algorithm:" + macAlgString); + return null; + } + + // (5) put MAC value from (3) in PopLinkWitnessV2 + PopLinkWitnessV2 popLinkWitnessV2 = + new PopLinkWitnessV2(keyGenAlg, macAlg, + new OCTET_STRING(finalDigest)); + /* + * for CRMF, needs to go into CRMF controls field of the CertRequest structure. + * for PKCS#10, needs to go into the aributes field of CertificationRequestInfo structure + * - return the PopLinkWitnessV2 for such surgical procedure + */ + System.out.println(method + "Successfully created PopLinkWitnessV2 control."); + + System.out.println(method + "returning..."); + System.out.println(""); + + return popLinkWitnessV2; + } + private static int addPopLinkWitnessAttr(int bpid, SEQUENCE controlSeq) { byte[] seed = { 0x10, 0x53, 0x42, 0x24, 0x1a, 0x2a, 0x35, 0x3c, @@ -1309,7 +1669,8 @@ public class CMCRequest { String dbdir = null, nickname = null; String tokenName = null; String ifilename = null, ofilename = null, password = null, format = null; - String decryptedPopEnable = "false", encryptedPopResponseFile=null, privKeyId = null, decryptedPopRequestFile= null; + String privKeyId = null; + String decryptedPopEnable = "false", encryptedPopResponseFile=null, decryptedPopRequestFile= null; String confirmCertEnable = "false", confirmCertIssuer = null, confirmCertSerial = null; String getCertEnable = "false", getCertIssuer = null, getCertSerial = null; String dataReturnEnable = "false", dataReturnData = null; @@ -1321,7 +1682,9 @@ public class CMCRequest { String revRequestInvalidityDatePresent = "false"; String identificationEnable = "false", identification = null; String identityProofEnable = "false", identityProofSharedSecret = null; - String identityProofV2Enable = "false", witnessSharedSecret = null, identityProofV2hashAlg = "SHA256", identityProofV2macAlg = "SHA256"; + String identityProofV2Enable = "false", identityProofV2hashAlg = "SHA256", identityProofV2macAlg = "SHA256"; + String witnessSharedSecret = null; //shared by identityProofV2 and popLinkWitnessV2 + String popLinkWitnessV2Enable = "false", popLinkWitnessV2keyGenAlg = "SHA256", popLinkWitnessV2macAlg = "SHA256"; String popLinkWitnessEnable = "false"; String bodyPartIDs = null, lraPopWitnessEnable = "false"; @@ -1378,6 +1741,8 @@ public class CMCRequest { ofilename = val; } else if (name.equals("input")) { ifilename = val; + } else if (name.equals("numRequests")) { + numRequests = val; } else if (name.equals("decryptedPop.enable")) { decryptedPopEnable = val; } else if (name.equals("encryptedPopResponseFile")) { @@ -1430,14 +1795,21 @@ public class CMCRequest { identificationEnable = val; } else if (name.equals("identification")) { identification = val; - } else if (name.equals("identityProofV2.enable")) { - identityProofV2Enable = val; } else if (name.equals("witness.sharedSecret")) { witnessSharedSecret = val; + } else if (name.equals("identityProofV2.enable")) { + identityProofV2Enable = val; } else if (name.equals("identityProofV2.hashAlg")) { identityProofV2hashAlg = val; } else if (name.equals("identityProofV2.macAlg")) { identityProofV2macAlg = val; + } else if (name.equals("popLinkWitnessV2.enable")) { + popLinkWitnessV2Enable = val; + } else if (name.equals("popLinkWitnessV2.keyGenAlg")) { + popLinkWitnessV2keyGenAlg = val; + } else if (name.equals("popLinkWitnessV2.macAlg")) { + popLinkWitnessV2macAlg = val; + /* the following are outdated */ } else if (name.equals("identityProof.enable")) { identityProofEnable = val; } else if (name.equals("identityProof.sharedSecret")) { @@ -1448,8 +1820,6 @@ public class CMCRequest { lraPopWitnessEnable = val; } else if (name.equals("LraPopWitness.bodyPartIDs")) { bodyPartIDs = val; - } else if (name.equals("numRequests")) { - numRequests = val; } } } @@ -1518,13 +1888,14 @@ public class CMCRequest { //cfu ContentInfo cmcblob = null; PKIData pkidata = null; - if (decryptedPopEnable.equalsIgnoreCase("true")) { - PrivateKey privk = null; + PrivateKey privk = null; + if (decryptedPopEnable.equalsIgnoreCase("true") || + popLinkWitnessV2Enable.equalsIgnoreCase("true")) { if (privKeyId == null) { - System.out.println("ecryptedPop.enable = true, but privKeyId not specified."); + System.out.println("ecryptedPop.enable or popLinkWitnessV2 true, but privKeyId not specified."); printUsage(); } else { - System.out.println("got privKeyId: " + privKeyId); + System.out.println("got request privKeyId: " + privKeyId); byte[] keyIDb = CryptoUtil.string2byte(privKeyId); @@ -1538,7 +1909,9 @@ public class CMCRequest { System.exit(1); } } + } + if (decryptedPopEnable.equalsIgnoreCase("true")) { if (encryptedPopResponseFile == null) { System.out.println("ecryptedPop.enable = true, but encryptedPopResponseFile is not specified."); printUsage(); @@ -1688,7 +2061,9 @@ public class CMCRequest { if (senderNonceEnable.equalsIgnoreCase("true")) bpid = addSenderNonceAttr(bpid, controlSeq, senderNonce); - if (popLinkWitnessEnable.equalsIgnoreCase("true")) + //popLinkWitnessV2 takes precedence + if (!popLinkWitnessV2Enable.equalsIgnoreCase("true") & + popLinkWitnessEnable.equalsIgnoreCase("true")) bpid = addPopLinkWitnessAttr(bpid, controlSeq); SEQUENCE otherMsgSeq = new SEQUENCE(); @@ -1711,9 +2086,13 @@ public class CMCRequest { format, transactionMgtEnable, transactionMgtId, identificationEnable, identification, identityProofEnable, identityProofSharedSecret, - identityProofV2Enable, witnessSharedSecret, + witnessSharedSecret, + identityProofV2Enable, identityProofV2hashAlg, identityProofV2macAlg, - controlSeq, otherMsgSeq, bpid); + popLinkWitnessV2Enable, + popLinkWitnessV2keyGenAlg, popLinkWitnessV2macAlg, + controlSeq, otherMsgSeq, bpid, + token, privk); if (pkidata == null) { System.out.println("pkidata null after createPKIData(). Exiting with error"); diff --git a/base/java-tools/src/com/netscape/cmstools/CRMFPopClient.java b/base/java-tools/src/com/netscape/cmstools/CRMFPopClient.java index 901528c..e8271b0 100644 --- a/base/java-tools/src/com/netscape/cmstools/CRMFPopClient.java +++ b/base/java-tools/src/com/netscape/cmstools/CRMFPopClient.java @@ -577,8 +577,10 @@ public class CRMFPopClient { SEQUENCE seq = new SEQUENCE(); seq.addElement(new AVA(new OBJECT_IDENTIFIER("1.3.6.1.5.5.7.5.1.4"), opts)); + /* OCTET_STRING ostr = createIDPOPLinkWitness(); seq.addElement(new AVA(OBJECT_IDENTIFIER.id_cmc_idPOPLinkWitness, ostr)); + */ return new CertRequest(new INTEGER(1), certTemplate, seq); } @@ -657,10 +659,10 @@ public class CRMFPopClient { Signature signer; if (algorithm.equals("rsa")) { - signer = token.getSignatureContext(SignatureAlgorithm.RSASignatureWithMD5Digest); + signer = token.getSignatureContext(SignatureAlgorithm.RSASignatureWithSHA256Digest); } else if (algorithm.equals("ec")) { - signer = token.getSignatureContext(SignatureAlgorithm.ECSignatureWithSHA1Digest); + signer = token.getSignatureContext(SignatureAlgorithm.ECSignatureWithSHA256Digest); } else { throw new Exception("Unknown algorithm: " + algorithm); @@ -675,10 +677,10 @@ public class CRMFPopClient { AlgorithmIdentifier algorithmID; if (algorithm.equals("rsa")) { - algorithmID = new AlgorithmIdentifier(SignatureAlgorithm.RSASignatureWithMD5Digest.toOID(), null); + algorithmID = new AlgorithmIdentifier(SignatureAlgorithm.RSASignatureWithSHA256Digest.toOID(), null); } else if (algorithm.equals("ec")) { - algorithmID = new AlgorithmIdentifier(SignatureAlgorithm.ECSignatureWithSHA1Digest.toOID(), null); + algorithmID = new AlgorithmIdentifier(SignatureAlgorithm.ECSignatureWithSHA256Digest.toOID(), null); } else { throw new Exception("Unknown algorithm: " + algorithm); diff --git a/base/java-tools/src/com/netscape/cmstools/PKCS10Client.java b/base/java-tools/src/com/netscape/cmstools/PKCS10Client.java index 57f8792..fd1d087 100644 --- a/base/java-tools/src/com/netscape/cmstools/PKCS10Client.java +++ b/base/java-tools/src/com/netscape/cmstools/PKCS10Client.java @@ -22,14 +22,12 @@ import java.io.FileOutputStream; import java.io.IOException; import java.io.PrintStream; import java.security.KeyPair; -import java.security.MessageDigest; import java.security.PublicKey; import org.mozilla.jss.CryptoManager; import org.mozilla.jss.asn1.BMPString; import org.mozilla.jss.asn1.INTEGER; import org.mozilla.jss.asn1.OBJECT_IDENTIFIER; -import org.mozilla.jss.asn1.OCTET_STRING; import org.mozilla.jss.asn1.PrintableString; import org.mozilla.jss.asn1.SET; import org.mozilla.jss.asn1.TeletexString; @@ -38,17 +36,16 @@ import org.mozilla.jss.asn1.UniversalString; import org.mozilla.jss.crypto.CryptoToken; import org.mozilla.jss.crypto.KeyPairAlgorithm; import org.mozilla.jss.crypto.KeyPairGenerator; +import org.mozilla.jss.crypto.PrivateKey; import org.mozilla.jss.crypto.SignatureAlgorithm; import org.mozilla.jss.pkcs10.CertificationRequest; import org.mozilla.jss.pkcs10.CertificationRequestInfo; import org.mozilla.jss.pkix.primitive.AVA; -import org.mozilla.jss.pkix.primitive.Attribute; import org.mozilla.jss.pkix.primitive.Name; import org.mozilla.jss.pkix.primitive.SubjectPublicKeyInfo; import org.mozilla.jss.util.Password; import com.netscape.cmsutil.crypto.CryptoUtil; -import com.netscape.cmsutil.util.HMACDigest; import com.netscape.cmsutil.util.Utils; import netscape.security.pkcs.PKCS10; @@ -248,6 +245,8 @@ public class PKCS10Client { System.out.println("PKCS10Client: key pair generated."); //key pair generated"); + /*** leave out this test code; cmc can add popLinkwitnessV2; + // Add idPOPLinkWitness control String secretValue = "testing"; byte[] key1 = null; @@ -255,7 +254,7 @@ public class PKCS10Client { MessageDigest SHA1Digest = MessageDigest.getInstance("SHA1"); key1 = SHA1Digest.digest(secretValue.getBytes()); - /* seed */ + // seed byte[] b = { 0x10, 0x53, 0x42, 0x24, 0x1a, 0x2a, 0x35, 0x3c, 0x7a, 0x52, 0x54, 0x56, 0x71, 0x65, 0x66, 0x4c, @@ -272,9 +271,10 @@ public class PKCS10Client { OCTET_STRING ostr = new OCTET_STRING(finalDigest); Attribute attr = new Attribute(OBJECT_IDENTIFIER.id_cmc_idPOPLinkWitness, ostr); + ***/ SET attributes = new SET(); - attributes.addElement(attr); + //attributes.addElement(attr); Name n = getJssName(enable_encoding, subjectName); SubjectPublicKeyInfo subjectPub = new SubjectPublicKeyInfo(pair.getPublic()); System.out.println("PKCS10Client: pair.getPublic() called."); @@ -286,7 +286,7 @@ public class PKCS10Client { if (alg.equals("rsa")) { CertificationRequest certRequest = null; certRequest = new CertificationRequest(certReqInfo, - pair.getPrivate(), SignatureAlgorithm.RSASignatureWithMD5Digest); + pair.getPrivate(), SignatureAlgorithm.RSASignatureWithSHA256Digest); System.out.println("PKCS10Client: CertificationRequest created."); ByteArrayOutputStream bos = new ByteArrayOutputStream(); @@ -323,6 +323,14 @@ public class PKCS10Client { b64E = CryptoUtil.base64Encode(certReqb); } + // print out keyid to be used in cmc popLinkWitnessV2 + PrivateKey privateKey = (PrivateKey) pair.getPrivate(); + @SuppressWarnings("deprecation") + byte id[] = privateKey.getUniqueID(); + String kid = CryptoUtil.byte2string(id); + System.out.println("Keypair private key id: " + kid); + System.out.println(""); + System.out.println(RFC7468_HEADER); System.out.println(b64E); System.out.println(RFC7468_TRAILER); diff --git a/base/server/cms/src/com/netscape/cms/profile/common/EnrollProfile.java b/base/server/cms/src/com/netscape/cms/profile/common/EnrollProfile.java index f4a59d2..b8053c1 100644 --- a/base/server/cms/src/com/netscape/cms/profile/common/EnrollProfile.java +++ b/base/server/cms/src/com/netscape/cms/profile/common/EnrollProfile.java @@ -55,6 +55,7 @@ import org.mozilla.jss.pkix.cmc.IdentityProofV2; import org.mozilla.jss.pkix.cmc.LraPopWitness; import org.mozilla.jss.pkix.cmc.OtherMsg; import org.mozilla.jss.pkix.cmc.PKIData; +import org.mozilla.jss.pkix.cmc.PopLinkWitnessV2; import org.mozilla.jss.pkix.cmc.TaggedAttribute; import org.mozilla.jss.pkix.cmc.TaggedCertificationRequest; import org.mozilla.jss.pkix.cmc.TaggedRequest; @@ -64,6 +65,7 @@ import org.mozilla.jss.pkix.crmf.CertTemplate; import org.mozilla.jss.pkix.crmf.PKIArchiveOptions; import org.mozilla.jss.pkix.crmf.ProofOfPossession; import org.mozilla.jss.pkix.primitive.AVA; +import org.mozilla.jss.pkix.primitive.AlgorithmIdentifier; import org.mozilla.jss.pkix.primitive.Attribute; import org.mozilla.jss.pkix.primitive.Name; import org.mozilla.jss.pkix.primitive.SubjectPublicKeyInfo; @@ -73,7 +75,6 @@ import com.netscape.certsrv.authentication.IAuthToken; import com.netscape.certsrv.authentication.ISharedToken; import com.netscape.certsrv.authority.IAuthority; import com.netscape.certsrv.base.EBaseException; -import com.netscape.certsrv.base.EPropertyNotFound; import com.netscape.certsrv.base.SessionContext; import com.netscape.certsrv.ca.ICertificateAuthority; import com.netscape.certsrv.logging.ILogger; @@ -147,6 +148,9 @@ public abstract class EnrollProfile extends BasicProfile */ public IRequest[] createRequests(IProfileContext ctx, Locale locale) throws EProfileException { + String method = "EnrollProfile: createRequests"; + CMS.debug(method + "begins"); + // determine how many requests should be created String cert_request_type = ctx.get(CTX_CERT_REQUEST_TYPE); String cert_request = ctx.get(CTX_CERT_REQUEST); @@ -155,7 +159,7 @@ public abstract class EnrollProfile extends BasicProfile /* cert_request_type can be null for the case of CMC */ if (cert_request_type == null) { - CMS.debug("EnrollProfile: request type is null"); + CMS.debug(method + " request type is null"); } int num_requests = 1; // default to 1 request @@ -178,10 +182,14 @@ public abstract class EnrollProfile extends BasicProfile */ // catch for invalid request cmc_msgs = parseCMC(locale, cert_request); - if (cmc_msgs == null) + if (cmc_msgs == null) { + CMS.debug(method + "parseCMC returns cmc_msgs null"); return null; - else + } else { num_requests = cmc_msgs.length; + CMS.debug(method + "parseCMC returns cmc_msgs num_requests=" + + num_requests); + } } // only 1 request for renewal @@ -360,7 +368,6 @@ public abstract class EnrollProfile extends BasicProfile throw new EBaseException(method + msg); } byte[] req_key_data = req.getExtDataInByteArray(IEnrollProfile.REQUEST_KEY); - netscape.security.x509.CertificateX509Key pubKey = null; if (req_key_data != null) { CMS.debug(method + "found user public key in request"); @@ -557,6 +564,7 @@ public abstract class EnrollProfile extends BasicProfile int numcontrols = controlSeq.size(); SEQUENCE reqSeq = pkiData.getReqSequence(); byte randomSeed[] = null; + UTF8String ident_s = null; SessionContext context = SessionContext.getContext(); if (!context.containsKey("numOfControls")) { if (numcontrols > 0) { @@ -592,6 +600,7 @@ public abstract class EnrollProfile extends BasicProfile id_cmc_identityProof = true; attr = attributes[i]; } else if (oid.equals(OBJECT_IDENTIFIER.id_cmc_idPOPLinkRandom)) { + CMS.debug(method + "id_cmc_idPOPLinkRandom true"); id_cmc_idPOPLinkRandom = true; vals = attributes[i].getValues(); } else { @@ -625,23 +634,31 @@ public abstract class EnrollProfile extends BasicProfile return null; } - UTF8String ident_s = null; if (id_cmc_identification) { if (ident == null) { msg = "id_cmc_identification contains null attribute value"; CMS.debug(method + msg); SEQUENCE bpids = getRequestBpids(reqSeq); context.put("identification", bpids); - return null; + + msg = " id_cmc_identification attribute value not found in"; + CMS.debug(method + msg); + throw new EProfileException( + CMS.getUserMessage(locale, "CMS_PROFILE_INVALID_REQUEST") + + msg); } ident_s = (UTF8String) (ASN1Util.decode(UTF8String.getTemplate(), ASN1Util.encode(ident.elementAt(0)))); if (ident_s == null) { - msg = "id_cmc_identification contains invalid content"; + msg = " id_cmc_identification contains invalid content"; CMS.debug(method + msg); SEQUENCE bpids = getRequestBpids(reqSeq); context.put("identification", bpids); - return null; + + CMS.debug(method + msg); + throw new EProfileException( + CMS.getUserMessage(locale, "CMS_PROFILE_INVALID_REQUEST") + + msg); } } @@ -650,7 +667,8 @@ public abstract class EnrollProfile extends BasicProfile if (!id_cmc_identification) { SEQUENCE bpids = getRequestBpids(reqSeq); context.put("identification", bpids); - msg = "id_cmc_identityProofV2 must be accompanied by id_cmc_identification in this server"; + context.put("identityProofV2", bpids); + msg = "id_cmc_identityProofV2 missing id_cmc_identification"; CMS.debug(method + msg); throw new EProfileException( CMS.getUserMessage(locale, "CMS_PROFILE_INVALID_REQUEST") + @@ -662,7 +680,11 @@ public abstract class EnrollProfile extends BasicProfile if (!valid) { SEQUENCE bpids = getRequestBpids(reqSeq); context.put("identityProofV2", bpids); - return null; + + msg = " in verifyIdentityProofV2"; + CMS.debug(method + msg); + throw new EProfileException(CMS.getUserMessage(locale, + "CMS_POI_VERIFICATION_ERROR")+ msg); } } else if (id_cmc_identityProof && (attr != null)) { boolean valid = verifyIdentityProof(attr, @@ -670,14 +692,20 @@ public abstract class EnrollProfile extends BasicProfile if (!valid) { SEQUENCE bpids = getRequestBpids(reqSeq); context.put("identityProof", bpids); - return null; + + msg = " in verifyIdentityProof"; + CMS.debug(method + msg); + throw new EProfileException(CMS.getUserMessage(locale, + "CMS_POI_VERIFICATION_ERROR")+ msg); } } if (id_cmc_idPOPLinkRandom && vals != null) { - OCTET_STRING ostr = (OCTET_STRING) (ASN1Util.decode(OCTET_STRING.getTemplate(), + OCTET_STRING ostr = + (OCTET_STRING) (ASN1Util.decode(OCTET_STRING.getTemplate(), ASN1Util.encode(vals.elementAt(0)))); randomSeed = ostr.toByteArray(); + CMS.debug(method + "got randomSeed"); } } // numcontrols > 0 } @@ -695,19 +723,55 @@ public abstract class EnrollProfile extends BasicProfile int nummsgs = reqSeq.size(); if (nummsgs > 0) { + msgs = new TaggedRequest[reqSeq.size()]; SEQUENCE bpids = new SEQUENCE(); + + /* TODO: add this in CS.cfg later: cmc.popLinkWitnessRequired=true + // enforce popLinkWitness (or V2) + boolean popLinkWitnessRequired = true; + try { + String configName = "cmc.popLinkWitnessRequired"; + CMS.debug(method + "getting :" + configName); + popLinkWitnessRequired = CMS.getConfigStore().getBoolean(configName, true); + CMS.debug(method + "cmc.popLinkWitnessRequired is " + popLinkWitnessRequired); + } catch (Exception e) { + // unlikely to get here + msg = method + " Failed to retrieve cmc.popLinkWitnessRequired"; + CMS.debug(msg); + throw new EProfileException(method + msg); + } +*/ + boolean valid = true; for (int i = 0; i < nummsgs; i++) { msgs[i] = (TaggedRequest) reqSeq.elementAt(i); - if (!context.containsKey("POPLinkWitness")) { + if (!context.containsKey("POPLinkWitnessV2") && + !context.containsKey("POPLinkWitness")) { if (randomSeed != null) { - valid = verifyPOPLinkWitness(randomSeed, msgs[i], bpids); - if (!valid || bpids.size() > 0) { - context.put("POPLinkWitness", bpids); - return null; + // verifyPOPLinkWitness() will determine if this is + // POPLinkWitnessV2 or POPLinkWitness + // If failure, context is set in verifyPOPLinkWitness + valid = verifyPOPLinkWitness(ident_s, randomSeed, msgs[i], bpids, context); + if (valid == false) { + if (context.containsKey("POPLinkWitnessV2")) + msg = " in POPLinkWitnessV2"; + else if (context.containsKey("POPLinkWitness")) + msg = " in POPLinkWitness"; + else + msg = " unspecified failure from verifyPOPLinkWitness"; + + CMS.debug(method + msg); + throw new EProfileException(CMS.getUserMessage(locale, + "MS_POP_LINK_WITNESS_VERIFICATION_ERROR")+ msg); } - } + /* TODO: for next cmc ticket, eliminate the extra trip of parseCMC if possible, or figure a way out to bypass this on 2nd trip + } else if (popLinkWitnessRequired == true) { + //popLinkWitnessRequired == true, must have randomSeed + CMS.debug(method + "popLinkWitness(V2) required; no randomSeed found"); + context.put("POPLinkWitnessV2", bpids); + return null;*/ + } //randomSeed != null } } } else @@ -715,8 +779,10 @@ public abstract class EnrollProfile extends BasicProfile CMS.debug(method + "ends"); return msgs; + } catch (EProfileException e) { + throw new EProfileException(e); } catch (Exception e) { - CMS.debug(method + "Unable to parse CMC request: " + e); + CMS.debug(method + e); throw new EProfileException( CMS.getUserMessage(locale, "CMS_PROFILE_INVALID_REQUEST"), e); } @@ -782,9 +848,9 @@ public abstract class EnrollProfile extends BasicProfile } byte[] cmc_msg = req.getExtDataInByteArray(IEnrollProfile.CTX_CERT_REQUEST); - if (pop_sysPubEncreyptedSession == null) { + if (cmc_msg == null) { msg = method + - "pop_sysPubEncreyptedSession not found in request:" + + "cmc_msg not found in request:" + reqId.toString(); CMS.debug(msg); return null; @@ -861,43 +927,125 @@ public abstract class EnrollProfile extends BasicProfile return reqId; } - private boolean verifyPOPLinkWitness(byte[] randomSeed, TaggedRequest req, - SEQUENCE bpids) { - ISharedToken tokenClass = null; - boolean sharedSecretFound = true; - String name = null; + /** + * getPopLinkWitnessV2control + * + * @author cfu + */ + protected PopLinkWitnessV2 getPopLinkWitnessV2control(ASN1Value value) { + String method = "EnrollProfile: getPopLinkWitnessV2control: "; + + ByteArrayInputStream bis = new ByteArrayInputStream( + ASN1Util.encode(value)); + PopLinkWitnessV2 popLinkWitnessV2 = null; + try { - name = CMS.getConfigStore().getString("cmc.sharedSecret.class"); - } catch (EPropertyNotFound e) { - CMS.debug("EnrollProfile: Failed to find the token class in the configuration file."); - sharedSecretFound = false; - } catch (EBaseException e) { - CMS.debug("EnrollProfile: Failed to find the token class in the configuration file."); - sharedSecretFound = false; + popLinkWitnessV2 = (PopLinkWitnessV2) (new PopLinkWitnessV2.Template()).decode(bis); + } catch (Exception e) { + CMS.debug(method + e); + } + return popLinkWitnessV2; + } + + /** + * verifyPopLinkWitnessV2 + * + * @author cfu + */ + protected boolean verifyPopLinkWitnessV2( + PopLinkWitnessV2 popLinkWitnessV2, + byte[] randomSeed, + String sharedSecret, + String ident_string) { + String method = "EnrollProfile: verifyPopLinkWitnessV2: "; + + if ((popLinkWitnessV2 == null) || + (randomSeed == null) || + (sharedSecret == null)) { + CMS.debug(method + " method parameters cannot be null"); + return false; + } + AlgorithmIdentifier keyGenAlg = popLinkWitnessV2.getKeyGenAlgorithm(); + AlgorithmIdentifier macAlg = popLinkWitnessV2.getMacAlgorithm(); + OCTET_STRING witness = popLinkWitnessV2.getWitness(); + if (keyGenAlg == null) { + CMS.debug(method + " keyGenAlg reurned by popLinkWitnessV2.getWitness is null"); + return false; + } + if (macAlg == null) { + CMS.debug(method + " macAlg reurned by popLinkWitnessV2.getWitness is null"); + return false; + } + if (witness == null) { + CMS.debug(method + " witness reurned by popLinkWitnessV2.getWitness is null"); + return false; } try { - tokenClass = (ISharedToken) Class.forName(name).newInstance(); - } catch (ClassNotFoundException e) { - CMS.debug("EnrollProfile: Failed to find class name: " + name); - sharedSecretFound = false; - } catch (InstantiationException e) { - CMS.debug("EnrollProfile: Failed to instantiate class: " + name); - sharedSecretFound = false; - } catch (IllegalAccessException e) { - CMS.debug("EnrollProfile: Illegal access: " + name); + DigestAlgorithm keyGenAlgID = DigestAlgorithm.fromOID(keyGenAlg.getOID()); + MessageDigest keyGenMDAlg = MessageDigest.getInstance(keyGenAlgID.toString()); + + HMACAlgorithm macAlgID = HMACAlgorithm.fromOID(macAlg.getOID()); + MessageDigest macMDAlg = MessageDigest + .getInstance(CryptoUtil.getHMACtoMessageDigestName(macAlgID.toString())); + + byte[] witness_bytes = witness.toByteArray(); + return verifyDigest( + (ident_string != null) ? (sharedSecret + ident_string).getBytes() : sharedSecret.getBytes(), + randomSeed, + witness_bytes, + keyGenMDAlg, macMDAlg); + } catch (NoSuchAlgorithmException e) { + CMS.debug(method + e); + return false; + } catch (Exception e) { + CMS.debug(method + e); + return false; + } + } + + /* + * verifyPOPLinkWitness now handles POPLinkWitnessV2; + */ + private boolean verifyPOPLinkWitness( + UTF8String ident, byte[] randomSeed, TaggedRequest req, + SEQUENCE bpids, SessionContext context) { + String method = "EnrollProfile: verifyPOPLinkWitness: "; + CMS.debug(method + "begins."); + + String ident_string = null; + if (ident != null) { + ident_string = ident.toString(); + } + + boolean sharedSecretFound = true; + String configName = "cmc.sharedSecret.class"; + String sharedSecret = null; + ISharedToken tokenClass = getSharedTokenClass(configName); + if (tokenClass == null) { + CMS.debug(method + " Failed to retrieve shared secret plugin class"); sharedSecretFound = false; + } else { + if (ident_string != null) { + sharedSecret = tokenClass.getSharedToken(ident_string); + } else { + sharedSecret = tokenClass.getSharedToken(mCMCData); + } + if (sharedSecret == null) + sharedSecretFound = false; } INTEGER reqId = null; byte[] bv = null; - String sharedSecret = null; - if (tokenClass != null) - sharedSecret = tokenClass.getSharedToken(mCMCData); + if (req.getType().equals(TaggedRequest.PKCS10)) { + String methodPos = method + "PKCS10: "; + CMS.debug(methodPos + "begins"); + TaggedCertificationRequest tcr = req.getTcr(); if (!sharedSecretFound) { bpids.addElement(tcr.getBodyPartID()); + context.put("POPLinkWitness", bpids); return false; } else { CertificationRequest creq = tcr.getCertificationRequest(); @@ -905,13 +1053,42 @@ public abstract class EnrollProfile extends BasicProfile SET attrs = cinfo.getAttributes(); for (int j = 0; j < attrs.size(); j++) { Attribute pkcs10Attr = (Attribute) attrs.elementAt(j); - if (pkcs10Attr.getType().equals(OBJECT_IDENTIFIER.id_cmc_idPOPLinkWitness)) { + if (pkcs10Attr.getType().equals(OBJECT_IDENTIFIER.id_cmc_popLinkWitnessV2)) { + CMS.debug(methodPos + "found id_cmc_popLinkWitnessV2"); + if (ident_string == null) { + bpids.addElement(reqId); + context.put("identification", bpids); + context.put("POPLinkWitnessV2", bpids); + String msg = "id_cmc_popLinkWitnessV2 must be accompanied by id_cmc_identification in this server"; + CMS.debug(methodPos + msg); + return false; + } + + SET witnessVal = pkcs10Attr.getValues(); + if (witnessVal.size() > 0) { + try { + PopLinkWitnessV2 popLinkWitnessV2 = getPopLinkWitnessV2control(witnessVal.elementAt(0)); + boolean valid = verifyPopLinkWitnessV2(popLinkWitnessV2, + randomSeed, + sharedSecret, + ident_string); + if (!valid) { + bpids.addElement(reqId); + context.put("POPLinkWitnessV2", bpids); + return valid; + } + return true; + } catch (Exception ex) { + CMS.debug(methodPos + ex); + return false; + } + } + } else if (pkcs10Attr.getType().equals(OBJECT_IDENTIFIER.id_cmc_idPOPLinkWitness)) { SET witnessVal = pkcs10Attr.getValues(); if (witnessVal.size() > 0) { try { - OCTET_STRING str = - (OCTET_STRING) (ASN1Util.decode(OCTET_STRING.getTemplate(), - ASN1Util.encode(witnessVal.elementAt(0)))); + OCTET_STRING str = (OCTET_STRING) (ASN1Util.decode(OCTET_STRING.getTemplate(), + ASN1Util.encode(witnessVal.elementAt(0)))); bv = str.toByteArray(); return verifyDigest(sharedSecret.getBytes(), randomSeed, bv); @@ -925,27 +1102,55 @@ public abstract class EnrollProfile extends BasicProfile return false; } } else if (req.getType().equals(TaggedRequest.CRMF)) { + String methodPos = method + "CRMF: "; + CMS.debug(methodPos + "begins"); + CertReqMsg crm = req.getCrm(); CertRequest certReq = crm.getCertReq(); reqId = certReq.getCertReqId(); if (!sharedSecretFound) { bpids.addElement(reqId); + context.put("POPLinkWitness", bpids); return false; } else { for (int i = 0; i < certReq.numControls(); i++) { AVA ava = certReq.controlAt(i); - if (ava.getOID().equals(OBJECT_IDENTIFIER.id_cmc_idPOPLinkWitness)) { + if (ava.getOID().equals(OBJECT_IDENTIFIER.id_cmc_popLinkWitnessV2)) { + CMS.debug(methodPos + "found id_cmc_popLinkWitnessV2"); + if (ident_string == null) { + bpids.addElement(reqId); + context.put("identification", bpids); + context.put("POPLinkWitnessV2", bpids); + String msg = "id_cmc_popLinkWitnessV2 must be accompanied by id_cmc_identification in this server"; + CMS.debug(methodPos + msg); + return false; + } + + ASN1Value value = ava.getValue(); + PopLinkWitnessV2 popLinkWitnessV2 = getPopLinkWitnessV2control(value); + + boolean valid = verifyPopLinkWitnessV2(popLinkWitnessV2, + randomSeed, + sharedSecret, + ident_string); + if (!valid) { + bpids.addElement(reqId); + context.put("POPLinkWitnessV2", bpids); + return valid; + } + } else if (ava.getOID().equals(OBJECT_IDENTIFIER.id_cmc_idPOPLinkWitness)) { + CMS.debug(methodPos + "found id_cmc_idPOPLinkWitness"); ASN1Value value = ava.getValue(); ByteArrayInputStream bis = new ByteArrayInputStream( ASN1Util.encode(value)); OCTET_STRING ostr = null; try { - ostr = (OCTET_STRING) - (new OCTET_STRING.Template()).decode(bis); + ostr = (OCTET_STRING) (new OCTET_STRING.Template()).decode(bis); bv = ostr.toByteArray(); } catch (Exception e) { bpids.addElement(reqId); + context.put("POPLinkWitness", bpids); return false; } @@ -953,6 +1158,7 @@ public abstract class EnrollProfile extends BasicProfile randomSeed, bv); if (!valid) { bpids.addElement(reqId); + context.put("POPLinkWitness", bpids); return valid; } } @@ -1006,10 +1212,7 @@ public abstract class EnrollProfile extends BasicProfile byte[] finalDigest = null; HMACDigest hmacDigest = new HMACDigest(macAlg, key); hmacDigest.update(text); - if (hmacDigest == null) { - CMS.debug(method + " hmacDigest null after hmacDigest.update"); - return false; - } + finalDigest = hmacDigest.digest(); if (finalDigest.length != bv.length) { @@ -1045,6 +1248,40 @@ public abstract class EnrollProfile extends BasicProfile return bpids; } + + ISharedToken getSharedTokenClass(String configName) { + String method = "EnrollProfile: getSharedTokenClass: "; + ISharedToken tokenClass = null; + + String name = null; + try { + CMS.debug(method + "getting :" + configName); + name = CMS.getConfigStore().getString(configName); + CMS.debug(method + "Shared Secret plugin class name retrieved:" + + name); + } catch (Exception e) { + CMS.debug(method + " Failed to retrieve shared secret plugin class name"); + return null; + } + + try { + tokenClass = (ISharedToken) Class.forName(name).newInstance(); + CMS.debug(method + "Shared Secret plugin class retrieved"); + } catch (ClassNotFoundException e) { + CMS.debug(method + " Failed to find class name: " + name); + return null; + } catch (InstantiationException e) { + CMS.debug("EnrollProfile: Failed to instantiate class: " + name); + return null; + } catch (IllegalAccessException e) { + CMS.debug(method + " Illegal access: " + name); + return null; + } + + return tokenClass; + } + + /** * verifyIdentityProofV2 handles IdentityProofV2 as defined by RFC5272 * @@ -1074,32 +1311,9 @@ public abstract class EnrollProfile extends BasicProfile return false; } - String name = null; - try { - String configName = "cmc.sharedSecret.class"; - CMS.debug(method + "getting :" + configName); - name = CMS.getConfigStore().getString(configName); - CMS.debug(method + "Shared Secret plugin class name retrieved:" + - name); - } catch (Exception e) { - CMS.debug(method + " Failed to retrieve shared secret plugin class name"); - return false; - } + String configName = "cmc.sharedSecret.class"; + ISharedToken tokenClass = getSharedTokenClass(configName); - ISharedToken tokenClass = null; - try { - tokenClass = (ISharedToken) Class.forName(name).newInstance(); - CMS.debug(method + "Shared Secret plugin class retrieved"); - } catch (ClassNotFoundException e) { - CMS.debug(method + " Failed to find class name: " + name); - return false; - } catch (InstantiationException e) { - CMS.debug("EnrollProfile: Failed to instantiate class: " + name); - return false; - } catch (IllegalAccessException e) { - CMS.debug(method + " Illegal access: " + name); - return false; - } if (tokenClass == null) { CMS.debug(method + " Failed to retrieve shared secret plugin class"); return false; @@ -1120,19 +1334,13 @@ public abstract class EnrollProfile extends BasicProfile try { IdentityProofV2 idV2val = (IdentityProofV2) (ASN1Util.decode(IdentityProofV2.getTemplate(), ASN1Util.encode(vals.elementAt(0)))); - /** - * TODO: cfu: - * phase2: getting configurable allowable hashing and mac algorithms - */ DigestAlgorithm hashAlgID = DigestAlgorithm.fromOID(idV2val.getHashAlgID().getOID()); MessageDigest hashAlg = MessageDigest.getInstance(hashAlgID.toString()); - // TODO: check against CA allowed algs later HMACAlgorithm macAlgId = HMACAlgorithm.fromOID(idV2val.getMacAlgId().getOID()); MessageDigest macAlg = MessageDigest .getInstance(CryptoUtil.getHMACtoMessageDigestName(macAlgId.toString())); - // TODO: check against CA allowed algs later OCTET_STRING witness = idV2val.getWitness(); if (witness == null) { @@ -1155,32 +1363,18 @@ public abstract class EnrollProfile extends BasicProfile } // verifyIdentityProofV2 private boolean verifyIdentityProof(TaggedAttribute attr, SEQUENCE reqSeq) { + String method = "verifyIdentityProof: "; + SET vals = attr.getValues(); if (vals.size() < 1) return false; - String name = null; - try { - name = CMS.getConfigStore().getString("cmc.sharedSecret.class"); - } catch (EPropertyNotFound e) { - } catch (EBaseException e) { - } - if (name == null) + String configName = "cmc.sharedSecret.class"; + ISharedToken tokenClass = getSharedTokenClass(configName); + if (tokenClass == null) { + CMS.debug(method + " Failed to retrieve shared secret plugin class"); return false; - else { - ISharedToken tokenClass = null; - try { - tokenClass = (ISharedToken) Class.forName(name).newInstance(); - } catch (ClassNotFoundException e) { - CMS.debug("EnrollProfile: Failed to find class name: " + name); - return false; - } catch (InstantiationException e) { - CMS.debug("EnrollProfile: Failed to instantiate class: " + name); - return false; - } catch (IllegalAccessException e) { - CMS.debug("EnrollProfile: Illegal access: " + name); - return false; - } + } String token = tokenClass.getSharedToken(mCMCData); OCTET_STRING ostr = null; @@ -1188,20 +1382,20 @@ public abstract class EnrollProfile extends BasicProfile ostr = (OCTET_STRING) (ASN1Util.decode(OCTET_STRING.getTemplate(), ASN1Util.encode(vals.elementAt(0)))); } catch (InvalidBERException e) { - CMS.debug("EnrollProfile: Failed to decode the byte value."); + CMS.debug(method + "Failed to decode the byte value."); return false; } byte[] b = ostr.toByteArray(); byte[] text = ASN1Util.encode(reqSeq); return verifyDigest(token.getBytes(), text, b); - } } public void fillTaggedRequest(Locale locale, TaggedRequest tagreq, X509CertInfo info, IRequest req) throws EProfileException { String method = "EnrollProfile: fillTaggedRequest: "; + CMS.debug(method + "begins"); TaggedRequest.Type type = tagreq.getType(); if (type == null) { CMS.debug(method + "TaggedRequest type == null"); diff --git a/base/server/cms/src/com/netscape/cms/servlet/common/CMCOutputTemplate.java b/base/server/cms/src/com/netscape/cms/servlet/common/CMCOutputTemplate.java index ac690f2..c130a1e 100644 --- a/base/server/cms/src/com/netscape/cms/servlet/common/CMCOutputTemplate.java +++ b/base/server/cms/src/com/netscape/cms/servlet/common/CMCOutputTemplate.java @@ -268,6 +268,18 @@ public class CMCOutputTemplate { controlSeq.addElement(tagattr); } + SEQUENCE POPLinkWitnessV2Bpids = (SEQUENCE) context.get("POPLinkWitnessV2"); + if (POPLinkWitnessV2Bpids != null && POPLinkWitnessV2Bpids.size() > 0) { + OtherInfo otherInfo = new OtherInfo(OtherInfo.FAIL, + new INTEGER(OtherInfo.BAD_REQUEST), null); + cmcStatusInfo = new CMCStatusInfo(CMCStatusInfo.FAILED, + POPLinkWitnessV2Bpids, (String) null, otherInfo); + tagattr = new TaggedAttribute( + new INTEGER(bpid++), + OBJECT_IDENTIFIER.id_cmc_cMCStatusInfo, cmcStatusInfo); + controlSeq.addElement(tagattr); + } + SEQUENCE POPLinkWitnessBpids = (SEQUENCE) context.get("POPLinkWitness"); if (POPLinkWitnessBpids != null && POPLinkWitnessBpids.size() > 0) { OtherInfo otherInfo = new OtherInfo(OtherInfo.FAIL, diff --git a/base/server/cmsbundle/src/UserMessages.properties b/base/server/cmsbundle/src/UserMessages.properties index bc7f8cf..bf96f90 100644 --- a/base/server/cmsbundle/src/UserMessages.properties +++ b/base/server/cmsbundle/src/UserMessages.properties @@ -306,6 +306,8 @@ CMS_ADMIN_SRVLT_CERT_VALIDATE_FAILED=Imported cert has not been verified to be v # ProfileSubmitServlet ####################################################### CMS_POP_VERIFICATION_ERROR=Proof-of-Possession Verification Failed +CMS_POI_VERIFICATION_ERROR=Proof-of-Identification Verification Failed +CMS_POP_LINK_WITNESS_VERIFICATION_ERROR=POP Link Witness Verification Failed CMS_AUTHENTICATION_AGENT_NAME=Agent Authentication CMS_AUTHENTICATION_AGENT_TEXT=This plugin authenticates agents using a certificate. CMS_AUTHENTICATION_SSL_CLIENT_NAME=SSL Client Authentication -- 2.7.4
_______________________________________________ Pki-devel mailing list Pki-devel@redhat.com https://www.redhat.com/mailman/listinfo/pki-devel