Cond ACK.
Looks good.
I just put a few minor suggestions to take care of in the attachment, which is
merely the original patch with comments
interspersed, identified with <jmange></jmagne>
----- Original Message -----
From: "Christina Fu" <c...@redhat.com>
To: pki-devel@redhat.com
Sent: Thursday, April 13, 2017 5:03:06 PM
Subject: [Pki-devel] [PATCH] #2614 CMC: id-cmc-popLinkWitnessV2 feature
implementation
Please review.
thanks!
Christina
_______________________________________________
Pki-devel mailing list
Pki-devel@redhat.com
https://www.redhat.com/mailman/listinfo/pki-devel
>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
+ *
+ */
<jmagne>
check for null to avoid null pointer exception. I know it's just the tool, but it would be ugly for the user
</jmagne>
+ 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;
<jmagne>
Do all these new members like popLinkWitnessV2Enable need to be initialized somewhere
</jmagne>
@@ -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);
+
<jmagne> no check for shared secret being null, will cause null pointer exception
</jmagne>
+ 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();
+
<jmagne>
I guess we don't need this comment now.
</jmagne>
+ /* 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);
<jmagne>
Should we throw the exception here or is returning null good enough?
</jmagne>
+ } 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