diff options
| author | Christina Fu <cfu@redhat.com> | 2017-05-15 18:15:36 -0700 |
|---|---|---|
| committer | Christina Fu <cfu@redhat.com> | 2017-05-17 11:45:14 -0700 |
| commit | 3c43b1119ca978c296a38a9fe404e1c0cdcdab63 (patch) | |
| tree | e232c34a1f4fdba15737e6d55c24ecfdaccfce13 /base/java-tools/src/com/netscape/cmstools | |
| parent | 75f588c291c1ab27e1e2b4edaa4c254a8bbc21a2 (diff) | |
| download | pki-3c43b1119ca978c296a38a9fe404e1c0cdcdab63.tar.gz pki-3c43b1119ca978c296a38a9fe404e1c0cdcdab63.tar.xz pki-3c43b1119ca978c296a38a9fe404e1c0cdcdab63.zip | |
Tocket2673- CMC: allow enrollment key signed (self-signed) CMC with identity proof
This patch implements the self-signed CMC requests, where the request is signed by the public key of the underlying request (PKCS#10 or CRMF). The scenario for when this method is used is when there was no existing signing cert for the user has been issued before, and once it is issued, it can be used to sign subsequent cert requests by the same user. The new enrollment profile introduced is : caFullCMCSelfSignedCert.cfg The new option introduced to both CRMFPopClient and PKCS10Client is "-y" which will add the required SubjectKeyIdentifier to the underlying request. When a CMC request is self-signed, no auditSubjectID is available until Identification Proof (v2) is verified, however, the cert subject DN is recorded in log as soon as it was available for additional information. Auditing is adjusted. More will come in the next couple CMC patches.
Diffstat (limited to 'base/java-tools/src/com/netscape/cmstools')
3 files changed, 213 insertions, 72 deletions
diff --git a/base/java-tools/src/com/netscape/cmstools/CMCRequest.java b/base/java-tools/src/com/netscape/cmstools/CMCRequest.java index ac523ad24..6e27cb100 100644 --- a/base/java-tools/src/com/netscape/cmstools/CMCRequest.java +++ b/base/java-tools/src/com/netscape/cmstools/CMCRequest.java @@ -103,6 +103,9 @@ import com.netscape.cmsutil.util.HMACDigest; import com.netscape.cmsutil.util.Utils; import netscape.security.pkcs.PKCS10; +import netscape.security.x509.KeyIdentifier; +import netscape.security.x509.PKIXExtensions; +import netscape.security.x509.SubjectKeyIdentifierExtension; import netscape.security.x509.X500Name; import netscape.security.x509.X509CertImpl; @@ -121,6 +124,7 @@ public class CMCRequest { public static final int ARGC = 1; public static final String HEADER = "-----BEGIN"; public static final String TRAILER = "-----END"; + public static SubjectKeyIdentifierExtension skiExtn = null; void cleanArgs(String[] s) { @@ -193,7 +197,7 @@ public class CMCRequest { } /** - * signData signs the request PKIData + * signData signs the request PKIData using existing cert * * @param signerCert the certificate of the authorized signer of the CMC revocation request. * @param nickname the nickname of the certificate inside the token. @@ -212,6 +216,15 @@ public class CMCRequest { SignedData req = null; System.out.println(method + "begins: "); + if (signerCert == null || + tokenName == null || + nickname == null || + manager == null || + pkidata == null) { + System.out.println(method + "method parameters cannot be null"); + System.exit(1); + } + try { java.security.PrivateKey privKey = null; SignerIdentifier si = null; @@ -232,7 +245,72 @@ public class CMCRequest { privKey = getPrivateKey(tokenName, nickname); if (privKey != null) System.out.println(method + " got signer privKey"); + else { + System.out.println(method + " signer privKey not foudn on token"); + System.exit(1); + } + + org.mozilla.jss.crypto.X509Certificate[] certChain = manager.buildCertificateChain(signerCert); + req = createSignedData(privKey, si, certChain, pkidata); + + System.out.println(method + "signed request generated."); + } catch (Exception e) { + e.printStackTrace(); + System.exit(1); + } + + return req; + } + + /* + * signData self-signs the PKIData using the private key that matches + * the public key in the request + */ + static SignedData signData( + java.security.PrivateKey privKey, + PKIData pkidata) { + String method = "signData for selfSign: "; + System.out.println(method + "begins: "); + SignedData req = null; + + if (privKey == null || + pkidata == null) { + System.out.println(method + "method parameters cannot be null"); + System.exit(1); + } + + KeyIdentifier keyIdObj = null; + try { + keyIdObj = (KeyIdentifier) skiExtn.get(SubjectKeyIdentifierExtension.KEY_ID); + SignerIdentifier si = new SignerIdentifier( + SignerIdentifier.SUBJECT_KEY_IDENTIFIER, + null, new OCTET_STRING(keyIdObj.getIdentifier())); + req = createSignedData(privKey, si, null /*certChain*/, pkidata); + } catch (Exception e) { + e.printStackTrace(); + System.exit(1); + } + return req; + } + static SignedData createSignedData( + java.security.PrivateKey privKey, + SignerIdentifier signerId, + org.mozilla.jss.crypto.X509Certificate[] certChain, + PKIData pkidata) { + + String method = "createSignedData: "; + System.out.println(method + "begins"); + if (privKey == null || + signerId == null || + pkidata == null) { + // certChain could be null + System.out.println(method + "method parameters cannot be null"); + System.exit(1); + } + + SignedData req = null; + try { EncapsulatedContentInfo ci = new EncapsulatedContentInfo(OBJECT_IDENTIFIER.id_cct_PKIData, pkidata); DigestAlgorithm digestAlg = null; SignatureAlgorithm signAlg = getSigningAlgFromPrivate(privKey); @@ -251,11 +329,18 @@ public class CMCRequest { pkidata.encode(ostream); digest = SHADigest.digest(ostream.toByteArray()); } catch (NoSuchAlgorithmException e) { - System.out.println(e); System.exit(1);} + System.out.println(e); + System.exit(1); + } System.out.println(method + "digest created for pkidata"); - SignerInfo signInfo = new SignerInfo(si, null, null, OBJECT_IDENTIFIER.id_cct_PKIData, digest, signAlg, + SignerInfo signInfo = new SignerInfo(signerId, null, null, + OBJECT_IDENTIFIER.id_cct_PKIData, digest, signAlg, (org.mozilla.jss.crypto.PrivateKey) privKey); + + String digestAlgName = signInfo.getDigestEncryptionAlgorithm().toString(); + System.out.println(method + "digest algorithm =" + digestAlgName); + SET signInfos = new SET(); signInfos.addElement(signInfo); @@ -266,21 +351,20 @@ public class CMCRequest { digestAlgs.addElement(ai); } - org.mozilla.jss.crypto.X509Certificate[] agentChain = manager.buildCertificateChain(signerCert); SET certs = new SET(); - - for (int i = 0; i < agentChain.length; i++) { - ANY cert = new ANY(agentChain[i].getEncoded()); - certs.addElement(cert); + if (certChain != null) { + System.out.println(method + "building cert chain"); + for (int i = 0; i < certChain.length; i++) { + ANY cert = new ANY(certChain[i].getEncoded()); + certs.addElement(cert); + } } req = new SignedData(digestAlgs, ci, certs, null, signInfos); - System.out.println(method + "signed request generated."); } catch (Exception e) { e.printStackTrace(); System.exit(1); } - return req; } @@ -325,6 +409,7 @@ public class CMCRequest { * @return request in PKIData */ static PKIData createPKIData( + String selfSign, String[] rValue, String format, String transactionMgtEnable, String transactionMgtId, String identificationEnable, String identification, @@ -387,13 +472,26 @@ public class CMCRequest { } certReqMsg = (CertReqMsg) crmfMsgs.elementAt(0); + CertRequest certReq = certReqMsg.getCertReq(); + CertTemplate certTemplate = certReq.getCertTemplate(); + if (selfSign.equals("true")) { + skiExtn = (SubjectKeyIdentifierExtension) CryptoUtil.getExtensionFromCertTemplate( + certTemplate, + PKIXExtensions.SubjectKey_Id); + if (skiExtn != null) { + System.out.println(method + + " SubjectKeyIdentifier extension found in self-signed request"); + } else { + System.out.println(method + + " SubjectKeyIdentifier extension missing in self-signed request"); + System.exit(1); + } + } 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)); @@ -449,6 +547,22 @@ public class CMCRequest { System.out.println(method + " Excception:" + e2.toString()); System.exit(1); } + + if (selfSign.equals("true")) { + try { + skiExtn = (SubjectKeyIdentifierExtension) CryptoUtil.getExtensionFromPKCS10( + pkcs, "SubjectKeyIdentifier"); + } catch (IOException e) { + System.out.println(method + "getting SubjectKeyIdentifiere..." + e); + } + + if (skiExtn != null) { + System.out.println(method + " SubjectKeyIdentifier extension found"); + } else { + System.out.println(method + " SubjectKeyIdentifier extension missing"); + System.exit(1); + } + } ByteArrayInputStream crInputStream = new ByteArrayInputStream( pkcs.toByteArray()); CertificationRequest cr = (CertificationRequest) CertificationRequest.getTemplate() @@ -661,8 +775,13 @@ public class CMCRequest { System.out.println(""); System.out.println("#nickname: nickname for agent certificate which will be used"); System.out.println("#to sign the CMC full request."); + System.out.println("#selfSign: if selfSign is true, the CMC request will be"); + System.out.println("#signed with the pairing private key of the request;"); + System.out.println("#and in which case the nickname will be ignored"); System.out.println("nickname=CMS Agent Certificate"); System.out.println(""); + System.out.println("selfSign=false"); + System.out.println(""); System.out.println("#dbdir: directory for cert8.db, key3.db and secmod.db"); System.out.println("dbdir=./"); System.out.println(""); @@ -1700,6 +1819,7 @@ public class CMCRequest { String popLinkWitnessV2Enable = "false", popLinkWitnessV2keyGenAlg = "SHA256", popLinkWitnessV2macAlg = "SHA256"; String popLinkWitnessEnable = "false"; String bodyPartIDs = null, lraPopWitnessEnable = "false"; + String selfSign = "false"; System.out.println(""); @@ -1760,6 +1880,8 @@ public class CMCRequest { decryptedPopEnable = val; } else if (name.equals("encryptedPopResponseFile")) { encryptedPopResponseFile = val; + } else if (name.equals("request.selfSign")) { + selfSign = val; } else if (name.equals("request.privKeyId")) { privKeyId = val; } else if (name.equals("decryptedPopRequestFile")) { @@ -1846,7 +1968,7 @@ public class CMCRequest { printUsage(); } - if (nickname == null) { + if (!selfSign.equals("true") && nickname == null) { System.out.println("Missing nickname."); printUsage(); } @@ -1898,14 +2020,14 @@ public class CMCRequest { System.out.println("got signerCert: "+ certname.toString()); } - //cfu ContentInfo cmcblob = null; PKIData pkidata = null; PrivateKey privk = null; - if (decryptedPopEnable.equalsIgnoreCase("true") || + if (selfSign.equalsIgnoreCase("true") || + decryptedPopEnable.equalsIgnoreCase("true") || popLinkWitnessV2Enable.equalsIgnoreCase("true")) { if (privKeyId == null) { - System.out.println("ecryptedPop.enable or popLinkWitnessV2 true, but privKeyId not specified."); + System.out.println("selfSign or ecryptedPop.enable or popLinkWitnessV2 true, but privKeyId not specified."); printUsage(); } else { System.out.println("got request privKeyId: " + privKeyId); @@ -2095,6 +2217,7 @@ public class CMCRequest { // create the request PKIData pkidata = createPKIData( + selfSign, requests, format, transactionMgtEnable, transactionMgtId, identificationEnable, identification, @@ -2114,7 +2237,16 @@ public class CMCRequest { } // sign the request - SignedData signedData = signData(signerCert, tokenName, nickname, cm, pkidata); + SignedData signedData = null; + if (selfSign.equalsIgnoreCase("true")) { + // selfSign signes with private key + System.out.println("selfSign is true..."); + signedData = signData(privk, pkidata); + } else { + // none selfSign signes with existing cert + System.out.println("selfSign is false..."); + signedData = signData(signerCert, tokenName, nickname, cm, pkidata); + } if (signedData == null) { System.out.println("signData() returns null. Exiting with error"); System.exit(1); diff --git a/base/java-tools/src/com/netscape/cmstools/CRMFPopClient.java b/base/java-tools/src/com/netscape/cmstools/CRMFPopClient.java index d0e5c2784..0057a1d52 100644 --- a/base/java-tools/src/com/netscape/cmstools/CRMFPopClient.java +++ b/base/java-tools/src/com/netscape/cmstools/CRMFPopClient.java @@ -86,6 +86,8 @@ import com.netscape.cmsutil.util.HMACDigest; import com.netscape.cmsutil.util.Utils; import netscape.security.util.WrappingParams; +import netscape.security.x509.KeyIdentifier; +import netscape.security.x509.PKIXExtensions; import netscape.security.x509.X500Name; /** @@ -196,6 +198,8 @@ public class CRMFPopClient { option.setArgName("keySet"); options.addOption(option); + options.addOption("y", false, "for Self-signed cmc."); + options.addOption("v", "verbose", false, "Run in verbose mode."); options.addOption(null, "help", false, "Show help message."); @@ -214,6 +218,9 @@ public class CRMFPopClient { System.out.println(" -k <true|false> Attribute value encoding in subject DN (default: false)"); System.out.println(" - true: enabled"); System.out.println(" - false: disabled"); + System.out.println(" -y <true|false> Add SubjectKeyIdentifier extension in case of self-signed CMC requests (default: false)"); + System.out.println(" - true: enabled"); + System.out.println(" - false: disabled"); System.out.println(" -a <rsa|ec> Key algorithm (default: rsa)"); System.out.println(" - rsa: RSA"); System.out.println(" - ec: ECC"); @@ -320,6 +327,8 @@ public class CRMFPopClient { int sensitive = Integer.parseInt(cmd.getOptionValue("s", "-1")); int extractable = Integer.parseInt(cmd.getOptionValue("e", "-1")); + boolean self_sign = cmd.hasOption("y"); + // get the key wrapping mechanism boolean keyWrap = true; if (cmd.hasOption("g")) { @@ -516,6 +525,7 @@ public class CRMFPopClient { if (verbose) System.out.println("Creating certificate request"); CertRequest certRequest = client.createCertRequest( + self_sign, token, transportCert, algorithm, keyPair, subject, archivalMechanism, wrappingKeySet); @@ -629,6 +639,19 @@ public class CRMFPopClient { Name subject, String archivalMechanism, String wrappingKeySet) throws Exception { + return createCertRequest(false, token, transportCert, algorithm, keyPair, + subject, archivalMechanism, wrappingKeySet); + } + + public CertRequest createCertRequest( + boolean self_sign, + CryptoToken token, + X509Certificate transportCert, + String algorithm, + KeyPair keyPair, + Name subject, + String archivalMechanism, + String wrappingKeySet) throws Exception { EncryptionAlgorithm encryptAlg = null; if (wrappingKeySet == null) { @@ -663,6 +686,15 @@ public class CRMFPopClient { seq.addElement(new AVA(OBJECT_IDENTIFIER.id_cmc_idPOPLinkWitness, ostr)); */ + if (self_sign) { // per rfc 5272 + System.out.println("CRMFPopClient: self_sign true. Generating SubjectKeyIdentifier extension."); + KeyIdentifier subjKeyId = CryptoUtil.createKeyIdentifier(keyPair); + OBJECT_IDENTIFIER oid = new OBJECT_IDENTIFIER(PKIXExtensions.SubjectKey_Id.toString()); + SEQUENCE extns = new SEQUENCE(); + extns.addElement(new AVA(oid, new OCTET_STRING(subjKeyId.getIdentifier()))); + certTemplate.setExtensions(extns); + } + return new CertRequest(new INTEGER(1), certTemplate, seq); } diff --git a/base/java-tools/src/com/netscape/cmstools/PKCS10Client.java b/base/java-tools/src/com/netscape/cmstools/PKCS10Client.java index fd1d08749..795c24be0 100644 --- a/base/java-tools/src/com/netscape/cmstools/PKCS10Client.java +++ b/base/java-tools/src/com/netscape/cmstools/PKCS10Client.java @@ -17,19 +17,15 @@ // --- END COPYRIGHT BLOCK --- package com.netscape.cmstools; -import java.io.ByteArrayOutputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.PrintStream; import java.security.KeyPair; -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.PrintableString; -import org.mozilla.jss.asn1.SET; import org.mozilla.jss.asn1.TeletexString; import org.mozilla.jss.asn1.UTF8String; import org.mozilla.jss.asn1.UniversalString; @@ -37,20 +33,17 @@ 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.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.Utils; import netscape.security.pkcs.PKCS10; +import netscape.security.x509.Extensions; +import netscape.security.x509.KeyIdentifier; +import netscape.security.x509.SubjectKeyIdentifierExtension; import netscape.security.x509.X500Name; -import netscape.security.x509.X509Key; /** * Generates an ECC or RSA key pair in the security database, constructs a @@ -91,6 +84,8 @@ public class PKCS10Client { " -x <true for SSL cert that does ECDH ECDSA; false otherwise; default false>\n"); System.out.println( " available ECC curve names (if provided by the crypto module): nistp256 (secp256r1),nistp384 (secp384r1),nistp521 (secp521r1),nistk163 (sect163k1),sect163r1,nistb163 (sect163r2),sect193r1,sect193r2,nistk233 (sect233k1),nistb233 (sect233r1),sect239k1,nistk283 (sect283k1),nistb283 (sect283r1),nistk409 (sect409k1),nistb409 (sect409r1),nistk571 (sect571k1),nistb571 (sect571r1),secp160k1,secp160r1,secp160r2,secp192k1,nistp192 (secp192r1, prime192v1),secp224k1,nistp224 (secp224r1),secp256k1,prime192v2,prime192v3,prime239v1,prime239v2,prime239v3,c2pnb163v1,c2pnb163v2,c2pnb163v3,c2pnb176v1,c2tnb191v1,c2tnb191v2,c2tnb191v3,c2pnb208w1,c2tnb239v1,c2tnb239v2,c2tnb239v3,c2pnb272w1,c2pnb304w1,c2tnb359w1,c2pnb368w1,c2tnb431r1,secp112r1,secp112r2,secp128r1,secp128r2,sect113r1,sect113r2,sect131r1,sect131r2\n"); + System.out.println( + "In addition: -y <true for adding SubjectKeyIdentifier extensionfor self-signed cmc requests; false otherwise; default false>\n"); } public static void main(String args[]) throws Exception { @@ -105,6 +100,8 @@ public class PKCS10Client { boolean ec_ssl_ecdh = false; int rsa_keylen = 2048; + boolean self_sign = false; + if (args.length < 4) { printUsage(); System.exit(1); @@ -171,6 +168,12 @@ public class PKCS10Client { subjectName = args[i+1]; } else if (name.equals("-h")) { tokenName = args[i+1]; + } else if (name.equals("-y")) { + String temp = args[i+1]; + if (temp.equals("true")) + self_sign = true; + else + self_sign = false; } else { System.out.println("Unrecognized argument(" + i + "): " + name); @@ -273,55 +276,29 @@ public class PKCS10Client { Attribute attr = new Attribute(OBJECT_IDENTIFIER.id_cmc_idPOPLinkWitness, ostr); ***/ - SET attributes = new SET(); - //attributes.addElement(attr); - Name n = getJssName(enable_encoding, subjectName); - SubjectPublicKeyInfo subjectPub = new SubjectPublicKeyInfo(pair.getPublic()); - System.out.println("PKCS10Client: pair.getPublic() called."); - CertificationRequestInfo certReqInfo = - new CertificationRequestInfo(new INTEGER(0), n, subjectPub, attributes); - System.out.println("PKCS10Client: CertificationRequestInfo() created."); - String b64E = ""; - if (alg.equals("rsa")) { - CertificationRequest certRequest = null; - certRequest = new CertificationRequest(certReqInfo, - pair.getPrivate(), SignatureAlgorithm.RSASignatureWithSHA256Digest); - System.out.println("PKCS10Client: CertificationRequest created."); + Extensions extns = new Extensions(); + if (self_sign) { // per rfc 5272 + System.out.println("PKCS10Client: self_sign true. Generating SubjectKeyIdentifier extension."); + KeyIdentifier subjKeyId = CryptoUtil.createKeyIdentifier(pair); + SubjectKeyIdentifierExtension extn = new SubjectKeyIdentifierExtension(false, + subjKeyId.getIdentifier()); + extns.add(extn); + } - ByteArrayOutputStream bos = new ByteArrayOutputStream(); - certRequest.encode(bos); - byte[] bb = bos.toByteArray(); + String b64E = ""; + PKCS10 certReq = CryptoUtil.createCertificationRequest( + subjectName, pair, extns); - System.out.println("PKCS10Client: calling Utils.b64encode."); - b64E = Utils.base64encode(bb); - System.out.println("PKCS10Client: b64encode completes."); - } else { // "ec" + if (certReq == null) { + System.out.println("PKCS10Client: cert request null"); + System.exit(1); + } else + System.out.println("PKCS10Client: CertificationRequest created."); + byte[] certReqb = certReq.toByteArray(); + b64E = CryptoUtil.base64Encode(certReqb); - CryptoToken t = cm.getThreadToken(); - System.out.println("PKCS10Client: token is: "+ t.getName()); - PublicKey pubk = pair.getPublic(); - if (pubk == null) { - System.out.println("PKCS10Client: pubk null."); - System.exit(1); - } - X509Key xKey = null; - byte pubk_encoded[] = pubk.getEncoded(); - xKey = CryptoUtil.getPublicX509ECCKey(pubk_encoded); - System.out.println("PKCS10Client: calling CryptoUtil.createCertificationRequest"); - PKCS10 certReq = CryptoUtil.createCertificationRequest( - subjectName, xKey, (org.mozilla.jss.crypto.PrivateKey) pair.getPrivate(), - "SHA256withEC"); - - System.out.println("PKCS10Client: created cert request"); - if (certReq == null) { - System.out.println("PKCS10Client: cert request null"); - System.exit(1); - } else - System.out.println("PKCS10Client: cert request not null"); - byte[] certReqb = certReq.toByteArray(); - b64E = CryptoUtil.base64Encode(certReqb); - } + System.out.println("PKCS10Client: b64encode completes."); // print out keyid to be used in cmc popLinkWitnessV2 PrivateKey privateKey = (PrivateKey) pair.getPrivate(); |
