diff --git a/base/common/src/com/netscape/certsrv/apps/CMS.java b/base/common/src/com/netscape/certsrv/apps/CMS.java index cc634cc088e..9df99ab0982 100644 --- a/base/common/src/com/netscape/certsrv/apps/CMS.java +++ b/base/common/src/com/netscape/certsrv/apps/CMS.java @@ -36,6 +36,7 @@ import org.mozilla.jss.CryptoManager.CertificateUsage; import org.mozilla.jss.util.PasswordCallback; +import com.netscape.certsrv.authentication.ISharedToken; import com.netscape.certsrv.acls.EACLsException; import com.netscape.certsrv.acls.IACL; import com.netscape.certsrv.authentication.IAuthSubsystem; @@ -1574,6 +1575,15 @@ public static IPasswordCheck getPasswordChecker() { return _engine.getPasswordChecker(); } + /** + * Retrieves the SharedToken class. + * + * @return named SharedToken class + */ + public static ISharedToken getSharedTokenClass(String configName) { + return _engine.getSharedTokenClass(configName); + } + /** * Puts a password entry into the single-sign on cache. * diff --git a/base/common/src/com/netscape/certsrv/apps/ICMSEngine.java b/base/common/src/com/netscape/certsrv/apps/ICMSEngine.java index 3655b0389a3..563b7c9c51f 100644 --- a/base/common/src/com/netscape/certsrv/apps/ICMSEngine.java +++ b/base/common/src/com/netscape/certsrv/apps/ICMSEngine.java @@ -38,6 +38,7 @@ import com.netscape.certsrv.acls.EACLsException; import com.netscape.certsrv.acls.IACL; +import com.netscape.certsrv.authentication.ISharedToken; import com.netscape.certsrv.authority.IAuthority; import com.netscape.certsrv.base.EBaseException; import com.netscape.certsrv.base.IArgBlock; @@ -680,6 +681,13 @@ public LDAPConnection getBoundConnection(String id, String host, int port, */ public ILdapConnFactory getLdapAnonConnFactory(String id) throws ELdapException; + /** + * Retrieves the named SharedToken class + * + * @return named shared token class + */ + public ISharedToken getSharedTokenClass(String configName); + /** * Retrieves the password check. * diff --git a/base/common/src/com/netscape/certsrv/base/SessionContext.java b/base/common/src/com/netscape/certsrv/base/SessionContext.java index 81debaee8c7..8bcb3c11e7a 100644 --- a/base/common/src/com/netscape/certsrv/base/SessionContext.java +++ b/base/common/src/com/netscape/certsrv/base/SessionContext.java @@ -52,6 +52,11 @@ public class SessionContext extends Hashtable { */ public static final String AUTH_MANAGER_ID = "authManagerId"; // String + /** + * Principal name object of the signed CMC request + */ + public static final String CMC_SIGNER_PRINCIPAL = "cmcSignerPrincipal"; + /** * User object of the authenticated user in the current thread. */ diff --git a/base/java-tools/src/com/netscape/cmstools/CMCRequest.java b/base/java-tools/src/com/netscape/cmstools/CMCRequest.java index 4adf22ba3db..00e03a7caac 100644 --- a/base/java-tools/src/com/netscape/cmstools/CMCRequest.java +++ b/base/java-tools/src/com/netscape/cmstools/CMCRequest.java @@ -72,15 +72,14 @@ import org.mozilla.jss.pkix.cmc.IdentityProofV2; import org.mozilla.jss.pkix.cmc.LraPopWitness; 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.RevokeRequest; import org.mozilla.jss.pkix.cmc.TaggedAttribute; import org.mozilla.jss.pkix.cmc.TaggedCertificationRequest; import org.mozilla.jss.pkix.cmc.TaggedRequest; -import org.mozilla.jss.pkix.cmmf.RevRequest; import org.mozilla.jss.pkix.cms.ContentInfo; import org.mozilla.jss.pkix.cms.EncapsulatedContentInfo; import org.mozilla.jss.pkix.cms.EncryptedContentInfo; @@ -374,14 +373,30 @@ static SignedData createSignedData( /** * getCMCBlob create and return the enrollment request. - * + * It now handles two types of data input: + * - SignedData (which is for signed data) + * - data (which is for unsigned data) * @return the CMC enrollment request encoded in base64 * */ - static ContentInfo getCMCBlob(SignedData req) { + static ContentInfo getCMCBlob(SignedData signedData, byte[] data) { String method = "getCMCBlob: "; System.out.println(method + "begins"); - ContentInfo fullEnrollmentReq = new ContentInfo(req); + ContentInfo fullEnrollmentReq = null; + if (signedData != null && data == null) { + System.out.println("getCMCBlob: generating signed data"); + fullEnrollmentReq = new ContentInfo(signedData); + } else if (data != null && signedData == null) { + System.out.println("getCMCBlob: generating unsigned data"); + fullEnrollmentReq = new ContentInfo(data); + } else if (signedData == null && data == null) { + System.out.println("getCMCBlob: both params are null"); + System.exit(1); + } else { + System.out.println("getCMCBlob: both params are not null; only one of them can be used, the other must be null"); + System.exit(1); + } + try { ByteArrayOutputStream bs = new ByteArrayOutputStream(); PrintStream ps = new PrintStream(bs); @@ -768,29 +783,32 @@ static void printUsage() { System.out.println(""); System.out.println("#input: full path for the PKCS10 request or CRMF request,"); System.out.println("#the content must be in Base-64 encoded format"); - System.out.println("#Multiple files are supported. They must be separated by space."); +// System.out.println("#Multiple files are supported. They must be separated by space."); + System.out.println("# in case of revocation, input will be ignored"); System.out.println("input=crmf.req"); System.out.println(""); System.out.println("#output: full path for the CMC request in binary format"); System.out.println("output=cmc.req"); System.out.println(""); - System.out.println("#tokenname: name of token where agent signing cert can be found (default is internal)"); + System.out.println("#tokenname: name of token where user signing cert can be found (default is internal)"); System.out.println("tokenname=internal"); 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("#nickname: nickname for user certificate which will be used"); + System.out.println("#to sign the CMC full request (enrollment or revocation)."); + System.out.println(""); 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("#signed with the pairing private key of the enrollment request;"); System.out.println("#and in which case the nickname will be ignored"); - System.out.println("nickname=CMS Agent Certificate"); + System.out.println("#If revRequest.sharedSecret is specified, then nickname will also be ignored."); + System.out.println("nickname=CMS User Signing 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(""); - System.out.println("#password: password for cert8.db which stores the agent"); - System.out.println("#certificate"); + System.out.println("#password: password for cert8.db which stores the user signing"); + System.out.println("#certificate and keys"); System.out.println("password=pass"); System.out.println(""); System.out.println("#format: request format, either pkcs10 or crmf"); @@ -844,13 +862,19 @@ static void printUsage() { System.out.println("#control. Otherwise, false."); System.out.println("revRequest.enable=false"); System.out.println(""); +/* System.out.println("#revRequest.nickname: The nickname for the revoke certificate"); System.out.println("revRequest.nickname=newuser's 102504a ID"); System.out.println(""); +*/ System.out.println("#revRequest.issuer: The issuer name for the certificate being"); - System.out.println("#revoked."); + System.out.println("#revoked. It only needs to be specified when the request is unsigned,;"); + System.out.println("#as in the case when sharedSecret is used;"); System.out.println("revRequest.issuer=cn=Certificate Manager,c=us"); System.out.println(""); + System.out.println("#revRequest.sharedSecret: The sharedSecret"); + System.out.println("revRequest.sharedSecret="); + System.out.println(""); System.out.println("#revRequest.serial: The serial number for the certificate being"); System.out.println("#revoked."); System.out.println("revRequest.serial=61"); @@ -861,9 +885,6 @@ static void printUsage() { System.out.println("# certificateHold, removeFromCRL"); System.out.println("revRequest.reason=unspecified"); System.out.println(""); - System.out.println("#revRequest.sharedSecret: The sharedSecret"); - System.out.println("revRequest.sharedSecret="); - System.out.println(""); System.out.println("#revRequest.comment: The human readable comment"); System.out.println("revRequest.comment="); System.out.println(""); @@ -972,27 +993,27 @@ private static int addConfirmCertAttr(int bpid, SEQUENCE seq, String confirmCert private static ENUMERATED toCRLReason(String str) { if (str.equalsIgnoreCase("unspecified")) { - return RevRequest.unspecified; + return RevokeRequest.unspecified; } else if (str.equalsIgnoreCase("keyCompromise")) { - return RevRequest.keyCompromise; + return RevokeRequest.keyCompromise; } else if (str.equalsIgnoreCase("caCompromise")) { - return RevRequest.cACompromise; + return RevokeRequest.cACompromise; } else if (str.equalsIgnoreCase("affiliationChanged")) { - return RevRequest.affiliationChanged; + return RevokeRequest.affiliationChanged; } else if (str.equalsIgnoreCase("superseded")) { - return RevRequest.superseded; + return RevokeRequest.superseded; } else if (str.equalsIgnoreCase("cessationOfOperation")) { - return RevRequest.cessationOfOperation; + return RevokeRequest.cessationOfOperation; } else if (str.equalsIgnoreCase("certificateHold")) { - return RevRequest.certificateHold; + return RevokeRequest.certificateHold; } else if (str.equalsIgnoreCase("removeFromCRL")) { - return RevRequest.removeFromCRL; + return RevokeRequest.removeFromCRL; } System.out.println("Unrecognized CRL reason"); System.exit(1); - return RevRequest.unspecified; + return RevokeRequest.unspecified; } /** @@ -1119,42 +1140,84 @@ private static int addIdentityProofAttr(int bpid, SEQUENCE seq, SEQUENCE reqSequ return bpid; } - private static int addRevRequestAttr(int bpid, SEQUENCE seq, SEQUENCE otherMsgSeq, CryptoToken token, String tokenName, String nickname, + /* + * addRevRequestAttr adds the RevokeRequest control + * If sharedSecret exist, issuer name needs to be supplied; + * else signing cert is needed to extract issuerName + */ + private static int addRevRequestAttr(int bpid, SEQUENCE seq, + CryptoToken token, X509Certificate revokeSignCert, String revRequestIssuer, String revRequestSerial, String revRequestReason, String revRequestSharedSecret, String revRequestComment, String invalidityDatePresent, CryptoManager manager) { + + String method = "addRevRequestAttr: "; try { - if (nickname.length() <= 0) { - System.out.println("The nickname for the certificate being revoked is null"); - System.exit(1); - } - String nickname1 = nickname; UTF8String comment = null; OCTET_STRING sharedSecret = null; GeneralizedTime d = null; - X500Name subjectname = new X500Name(revRequestIssuer); + X500Name issuerName = null; + + if ((revRequestSerial == null) || (revRequestSerial.length() <= 0)) { + System.out.println(method + "revocation serial number must be supplied"); + System.exit(1); + } + if ((revRequestReason == null) || (revRequestReason.length() <= 0)) { + System.out.println(method + "revocation reason must be supplied"); + System.exit(1); + } INTEGER snumber = new INTEGER(revRequestSerial); ENUMERATED reason = toCRLReason(revRequestReason); - if (revRequestSharedSecret.length() > 0) + + if ((revRequestSharedSecret != null) && (revRequestSharedSecret.length() > 0)) { sharedSecret = new OCTET_STRING(revRequestSharedSecret.getBytes()); - if (revRequestComment.length() > 0) + // in case of sharedSecret, + // issuer name will have to be provided; + // revokeSignCert is ignored; + if (revRequestIssuer == null) { + System.out.println(method + "issuer name must be supplied when shared secret is used"); + System.exit(1); + } + issuerName = new X500Name(revRequestIssuer); + } else { // signing case; revokeSignCert is required + if (revokeSignCert == null) { + System.out.println(method + "revokeSignCert must be supplied in the signing case"); + System.exit(1); + } + } + + if (revRequestComment != null && revRequestComment.length() > 0) comment = new UTF8String(revRequestComment); if (invalidityDatePresent.equals("true")) d = new GeneralizedTime(new Date()); - RevRequest revRequest = - new RevRequest(new ANY(subjectname.getEncoded()), snumber, - reason, d, sharedSecret, comment); - int revokeBpid = bpid; + + if (sharedSecret == null) { + System.out.println(method + "no sharedSecret found; request will be signed;"); + + // getting issuerName from revokeSignCert + byte[] certB = revokeSignCert.getEncoded(); + X509CertImpl impl = new X509CertImpl(certB); + issuerName = (X500Name) impl.getIssuerDN(); + } else { + System.out.println(method + "sharedSecret found; request will be unsigned;"); + } + + RevokeRequest revRequest = new RevokeRequest(new ANY(issuerName.getEncoded()), snumber, + reason, d, sharedSecret, comment); + TaggedAttribute revRequestControl = new TaggedAttribute( new INTEGER(bpid++), OBJECT_IDENTIFIER.id_cmc_revokeRequest, revRequest); seq.addElement(revRequestControl); + System.out.println(method + "RevokeRequest control created."); - if (sharedSecret != null) { - System.out.println("Successfully create revRequest control. bpid = " + (bpid - 1)); - System.out.println(""); - return bpid; - } + return bpid; +/* + * Constructing OtherMsg to include the SignerInfo makes no sense here + * as the outer layer SignedData would have SignerInfo. + * It is possibly done because the original code assumed a self-signed + * revocation request that is subsequently signed by an agent... + * which is not conforming to the RFC. EncapsulatedContentInfo revokeContent = new EncapsulatedContentInfo( OBJECT_IDENTIFIER.id_cct_PKIData, revRequestControl); @@ -1241,6 +1304,7 @@ private static int addRevRequestAttr(int bpid, SEQUENCE seq, SEQUENCE otherMsgSe otherMsgSeq.addElement(otherMsg); System.out.println("Successfully create revRequest control. bpid = " + (bpid - 1)); System.out.println(""); +*/ } catch (Exception e) { System.out.println("Error in creating revRequest control. Check the parameters. Exception="+ e.toString()); System.exit(1); @@ -1346,9 +1410,9 @@ private static int addSenderNonceAttr(int bpid, SEQUENCE seq, String nonce) { String salt = "lala123" + date.toString(); try { - MessageDigest SHA1Digest = MessageDigest.getInstance("SHA1"); + MessageDigest SHA256Digest = MessageDigest.getInstance("SHA256"); - dig = SHA1Digest.digest(salt.getBytes()); + dig = SHA256Digest.digest(salt.getBytes()); } catch (NoSuchAlgorithmException ex) { dig = salt.getBytes(); } @@ -1825,7 +1889,6 @@ public static void main(String[] s) { String dataReturnEnable = "false", dataReturnData = null; String transactionMgtEnable = "false", transactionMgtId = null; String senderNonceEnable = "false", senderNonce = null; - String revCertNickname = ""; String revRequestEnable = "false", revRequestIssuer = null, revRequestSerial = null; String revRequestReason = null, revRequestSharedSecret = null, revRequestComment = null; String revRequestInvalidityDatePresent = "false"; @@ -1941,8 +2004,6 @@ public static void main(String[] s) { revRequestComment = val; } else if (name.equals("revRequest.invalidityDatePresent")) { revRequestInvalidityDatePresent = val; - } else if (name.equals("revRequest.nickname")) { - revCertNickname = val; } else if (name.equals("identification.enable")) { identificationEnable = val; } else if (name.equals("identification")) { @@ -1985,7 +2046,8 @@ public static void main(String[] s) { printUsage(); } - if (!selfSign.equals("true") && nickname == null) { + if ((!selfSign.equals("true") && (revRequestSharedSecret == null)) + && nickname == null) { System.out.println("Missing nickname."); printUsage(); } @@ -2031,11 +2093,12 @@ public static void main(String[] s) { certname.append(tokenName); certname.append(":"); } - if (!selfSign.equals("true") && nickname != null) { + if ((!selfSign.equals("true") || (revRequestSharedSecret == null)) + && nickname != null) { certname.append(nickname); signerCert = cm.findCertByNickname(certname.toString()); if (signerCert != null) { - System.out.println("got signerCert: "+ certname.toString()); + System.out.println("got signerCert: " + certname.toString()); } } @@ -2065,6 +2128,7 @@ public static void main(String[] s) { } } + boolean isSharedSecretRevoke = false; if (decryptedPopEnable.equalsIgnoreCase("true")) { if (encryptedPopResponseFile == null) { System.out.println("ecryptedPop.enable = true, but encryptedPopResponseFile is not specified."); @@ -2091,7 +2155,7 @@ public static void main(String[] s) { } } else { // !decryptedPopEnable - if (ifilename == null) { + if (!revRequestEnable.equalsIgnoreCase("true") && ifilename == null) { System.out.println("Missing input filename for PKCS10 or CRMF."); printUsage(); } @@ -2109,14 +2173,17 @@ public static void main(String[] s) { } } - StringTokenizer tokenizer = new StringTokenizer(ifilename, " "); - String[] ifiles = new String[num]; - for (int i = 0; i < num; i++) { - String ss = tokenizer.nextToken(); - ifiles[i] = ss; - if (ss == null) { - System.out.println("Missing input file for the request."); - System.exit(1); + String[] ifiles = null; + if (revRequestEnable.equalsIgnoreCase("false")) { + StringTokenizer tokenizer = new StringTokenizer(ifilename, " "); + ifiles = new String[num]; + for (int i = 0; i < num; i++) { + String ss = tokenizer.nextToken(); + ifiles[i] = ss; + if (ss == null) { + System.out.println("Missing input file for the request."); + System.exit(1); + } } } @@ -2126,11 +2193,12 @@ public static void main(String[] s) { } if (format == null) { - System.out.println("Missing format."); - printUsage(); + System.out.println("Missing format..assume revocation"); + //printUsage(); } + String[] requests = new String[num]; - for (int i = 0; i < num; i++) { + for (int i = 0; i < num && revRequestEnable.equalsIgnoreCase("false") ; i++) { BufferedReader inputBlob = null; try { inputBlob = new BufferedReader(new InputStreamReader( @@ -2222,20 +2290,20 @@ public static void main(String[] s) { SEQUENCE otherMsgSeq = new SEQUENCE(); if (revRequestEnable.equalsIgnoreCase("true")) { - if (revRequestIssuer.length() == 0 || revRequestSerial.length() == 0 || - revRequestReason.length() == 0) { - System.out.println("Illegal parameters for revRequest control"); - printUsage(); - System.exit(1); + if ((revRequestSharedSecret!= null) + && (revRequestSharedSecret.length() > 0)) { + isSharedSecretRevoke = true; + //this will result in unsigned data } - bpid = addRevRequestAttr(bpid, controlSeq, otherMsgSeq, token, tokenName, revCertNickname, + bpid = addRevRequestAttr(bpid, controlSeq, token, signerCert, revRequestIssuer, revRequestSerial, revRequestReason, revRequestSharedSecret, revRequestComment, revRequestInvalidityDatePresent, cm); - } + pkidata = new PKIData(controlSeq, new SEQUENCE(), new SEQUENCE(), new SEQUENCE()); + } else { - // create the request PKIData - pkidata = createPKIData( + // create the request PKIData + pkidata = createPKIData( selfSign, requests, format, transactionMgtEnable, transactionMgtId, @@ -2248,6 +2316,7 @@ public static void main(String[] s) { popLinkWitnessV2keyGenAlg, popLinkWitnessV2macAlg, controlSeq, otherMsgSeq, bpid, token, privk); + } if (pkidata == null) { System.out.println("pkidata null after createPKIData(). Exiting with error"); @@ -2255,22 +2324,30 @@ public static void main(String[] s) { } } - // sign the request - SignedData signedData = null; - if (selfSign.equalsIgnoreCase("true")) { - // selfSign signs with private key - System.out.println("selfSign is true..."); - signedData = signData(privk, pkidata); + if (isSharedSecretRevoke) { + cmcblob = getCMCBlob(null, + ASN1Util.encode(pkidata)); } else { - // none selfSign signs 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); + + SignedData signedData = null; + + // sign the request + if (selfSign.equalsIgnoreCase("true")) { + // selfSign signs with private key + System.out.println("selfSign is true..."); + signedData = signData(privk, pkidata); + } else { + // none selfSign signs 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); + } + cmcblob = getCMCBlob(signedData, null); } - cmcblob = getCMCBlob(signedData); + if (cmcblob == null) { System.out.println("getCMCBlob() returns null. Exiting with error"); System.exit(1); diff --git a/base/java-tools/src/com/netscape/cmstools/CMCRevoke.java b/base/java-tools/src/com/netscape/cmstools/CMCRevoke.java index c2572e64b51..e46e8834ff9 100644 --- a/base/java-tools/src/com/netscape/cmstools/CMCRevoke.java +++ b/base/java-tools/src/com/netscape/cmstools/CMCRevoke.java @@ -75,6 +75,7 @@ public class CMCRevoke { public static final String RFC7468_TRAILER = "-----END CERTIFICATE REQUEST-----"; static String dValue = null, nValue = null, iValue = null, sValue = null, mValue = null, hValue = null, pValue = null, cValue = null; + static String tValue = null; public static final String CMS_BASE_CA_SIGNINGCERT_NOT_FOUND = "CA signing certificate not found"; public static final String PR_REQUEST_CMC = "CMC"; @@ -109,8 +110,9 @@ public static void main(String[] s) { "-d " + "-n " + "-i " + - "-s " + + "-s " + "-m " + + "-t " + "-p " + "-h " + "-c "); @@ -135,6 +137,8 @@ public static void main(String[] s) { mValue = cleanArgs(s[i].substring(2)); } else if (s[i].startsWith("-p")) { pValue = cleanArgs(s[i].substring(2)); + } else if (s[i].startsWith("-t")) { + tValue = cleanArgs(s[i].substring(2)); } else if (s[i].startsWith("-h")) { hValue = cleanArgs(s[i].substring(2)); } else if (s[i].startsWith("-c")) { @@ -143,8 +147,6 @@ public static void main(String[] s) { } // optional parameters - if (cValue == null) - cValue = ""; if (hValue == null) hValue = ""; @@ -160,7 +162,7 @@ else if (dValue.length() == 0 || nValue.length() == 0 || iValue.length() == 0 || "-d " + "-n " + "-i " + - "-s " + + "-s " + "-m " + "-p " + "-h " + @@ -191,9 +193,9 @@ else if (dValue.length() == 0 || nValue.length() == 0 || iValue.length() == 0 || token.login(pass); X509Certificate signerCert = getCertificate(cm, hValue, nValue); - String outBlob = createRevokeReq(hValue, signerCert, cm); + ContentInfo fullEnrollmentRequest = createRevokeReq(hValue, signerCert, cm); - printCMCRevokeRequest(outBlob); + printCMCRevokeRequest(fullEnrollmentRequest); } catch (Exception e) { e.printStackTrace(); System.exit(1); @@ -209,29 +211,48 @@ else if (dValue.length() == 0 || nValue.length() == 0 || iValue.length() == 0 || * * @param asciiBASE64Blob the ascii string of the request */ - static void printCMCRevokeRequest(String asciiBASE64Blob) { + static void printCMCRevokeRequest(ContentInfo fullEnrollmentReq) { + String method = "printCMCRevokeRequest: "; - // (6) Finally, print the actual CMCSigning blob to the + ByteArrayOutputStream os = new ByteArrayOutputStream(); + ByteArrayOutputStream bs = new ByteArrayOutputStream(); + PrintStream ps = new PrintStream(bs); + + if (fullEnrollmentReq == null) { + System.out.println(method + "param fullEnrollmentRequest is null"); + System.exit(1); + } + // format is PR_REQUEST_CMC + try { + fullEnrollmentReq.encode(os); + } catch (IOException e) { + System.out.println("CMCSigning: I/O error " + + "encountered during write():\n" + + e); + System.exit(1); + } + //ps.print(Utils.base64encode(os.toByteArray())); + // no line breaks for ease of copy/paste for CA acceptance + System.out.println(RFC7468_HEADER); + ps.print(Utils.base64encodeSingleLine(os.toByteArray())); + ////fullEnrollmentReq.print(ps); // no header/trailer + + String asciiBASE64Blob = bs.toString(); + System.out.println(asciiBASE64Blob + "\n" + RFC7468_TRAILER); + + // (6) Finally, print the actual CMCSigning binary blob to the // specified output file FileOutputStream outputBlob = null; try { outputBlob = new FileOutputStream("CMCRevoke.out"); + fullEnrollmentReq.encode(outputBlob); } catch (IOException e) { System.out.println("CMCSigning: unable to open file CMCRevoke.out for writing:\n" + e); return; } - System.out.println(RFC7468_HEADER); - System.out.println(asciiBASE64Blob + RFC7468_TRAILER); - try { - asciiBASE64Blob = RFC7468_HEADER + "\n" + asciiBASE64Blob + RFC7468_TRAILER; - outputBlob.write(asciiBASE64Blob.getBytes()); - } catch (IOException e) { - System.out.println("CMCSigning: I/O error " + - "encountered during write():\n" + - e); - } + System.out.println("\nCMC revocation binary blob written to CMCRevoke.out\n"); try { outputBlob.close(); @@ -280,12 +301,11 @@ public static X509Certificate getCertificate(CryptoManager manager, String token * @param manager the crypto manger. * @return the CMC revocation request encoded in base64 */ - static String createRevokeReq(String tokenname, X509Certificate signerCert, CryptoManager manager) { + static ContentInfo createRevokeReq(String tokenname, X509Certificate signerCert, CryptoManager manager) { java.security.PrivateKey privKey = null; SignerIdentifier si = null; ContentInfo fullEnrollmentReq = null; - String asciiBASE64Blob = null; try { @@ -305,8 +325,8 @@ static String createRevokeReq(String tokenname, X509Certificate signerCert, Cryp if (privKey == null) { System.out.println("CMCRevoke::createRevokeReq() - " + - "privKey is null!"); - return ""; + "privKey is null!"); + return null; } int bpid = 1; @@ -319,65 +339,64 @@ static String createRevokeReq(String tokenname, X509Certificate signerCert, Cryp byte[] dig; try { - MessageDigest SHA1Digest = MessageDigest.getInstance("SHA1"); + MessageDigest SHA2Digest = MessageDigest.getInstance("SHA256"); - dig = SHA1Digest.digest(salt.getBytes()); + dig = SHA2Digest.digest(salt.getBytes()); } catch (NoSuchAlgorithmException ex) { dig = salt.getBytes(); } String sn = Utils.base64encode(dig); - TaggedAttribute senderNonce = - new TaggedAttribute(new INTEGER(bpid++), OBJECT_IDENTIFIER.id_cmc_senderNonce, - new OCTET_STRING(sn.getBytes())); + TaggedAttribute senderNonce = new TaggedAttribute(new INTEGER(bpid++), OBJECT_IDENTIFIER.id_cmc_senderNonce, + new OCTET_STRING(sn.getBytes())); controlSeq.addElement(senderNonce); Name subjectName = new Name(); subjectName.addCommonName(iValue); - org.mozilla.jss.pkix.cmmf.RevRequest lRevokeRequest = - new org.mozilla.jss.pkix.cmmf.RevRequest(new ANY((new X500Name(iValue)).getEncoded()), - new INTEGER(sValue), - //org.mozilla.jss.pkix.cmmf.RevRequest.unspecified, - new ENUMERATED((new Integer(mValue)).longValue()), - null, - new OCTET_STRING(pValue.getBytes()), - new UTF8String(cValue.toCharArray())); + org.mozilla.jss.pkix.cmc.RevokeRequest lRevokeRequest = new org.mozilla.jss.pkix.cmc.RevokeRequest( + new ANY((new X500Name(iValue)).getEncoded()), + new INTEGER(sValue), + //org.mozilla.jss.pkix.cmc.RevokeRequest.unspecified, + new ENUMERATED((new Integer(mValue)).longValue()), + null, + (tValue != null) ? new OCTET_STRING(tValue.getBytes()) : null, + (cValue != null) ? new UTF8String(cValue.toCharArray()) : null); //byte[] encoded = ASN1Util.encode(lRevokeRequest); - //org.mozilla.jss.asn1.ASN1Template template = new org.mozilla.jss.pkix.cmmf.RevRequest.Template(); - //org.mozilla.jss.pkix.cmmf.RevRequest revRequest = (org.mozilla.jss.pkix.cmmf.RevRequest) + //org.mozilla.jss.asn1.ASN1Template template = new org.mozilla.jss.pkix.cmc.RevokeRequest.Template(); + //org.mozilla.jss.pkix.cmc.RevokeRequest revRequest = (org.mozilla.jss.pkix.cmc.RevokeRequest) // template.decode(new java.io.ByteArrayInputStream( // encoded)); - ByteArrayOutputStream os = new ByteArrayOutputStream(); - //lRevokeRequest.encode(os); // khai - TaggedAttribute revokeRequestTag = - new TaggedAttribute(new INTEGER(bpid++), OBJECT_IDENTIFIER.id_cmc_revokeRequest, - lRevokeRequest); + TaggedAttribute revokeRequestTag = new TaggedAttribute(new INTEGER(bpid++), + OBJECT_IDENTIFIER.id_cmc_revokeRequest, + lRevokeRequest); controlSeq.addElement(revokeRequestTag); PKIData pkidata = new PKIData(controlSeq, new SEQUENCE(), new SEQUENCE(), new SEQUENCE()); EncapsulatedContentInfo ci = new EncapsulatedContentInfo(OBJECT_IDENTIFIER.id_cct_PKIData, pkidata); - // SHA1 is the default digest Alg for now. DigestAlgorithm digestAlg = null; SignatureAlgorithm signAlg = null; - org.mozilla.jss.crypto.PrivateKey.Type signingKeyType = ((org.mozilla.jss.crypto.PrivateKey) privKey).getType(); + 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.RSASignatureWithSHA1Digest; + signAlg = SignatureAlgorithm.RSASignatureWithSHA256Digest; } else if (signingKeyType.equals(org.mozilla.jss.crypto.PrivateKey.Type.EC)) { - signAlg = SignatureAlgorithm.ECSignatureWithSHA1Digest; - } else if (signingKeyType.equals(org.mozilla.jss.crypto.PrivateKey.Type.DSA)) { - signAlg = SignatureAlgorithm.DSASignatureWithSHA1Digest; + signAlg = SignatureAlgorithm.ECSignatureWithSHA256Digest; + } else { + System.out.println("Algorithm not supported:" + + signingKeyType); + return null; } MessageDigest SHADigest = null; byte[] digest = null; try { - SHADigest = MessageDigest.getInstance("SHA1"); - digestAlg = DigestAlgorithm.SHA1; + SHADigest = MessageDigest.getInstance("SHA256"); + digestAlg = DigestAlgorithm.SHA256; ByteArrayOutputStream ostream = new ByteArrayOutputStream(); @@ -411,21 +430,11 @@ static String createRevokeReq(String tokenname, X509Certificate signerCert, Cryp fullEnrollmentReq = new ContentInfo(req); - ByteArrayOutputStream bs = new ByteArrayOutputStream(); - PrintStream ps = new PrintStream(bs); - - if (fullEnrollmentReq != null) { - // format is PR_REQUEST_CMC - fullEnrollmentReq.encode(os); - ps.print(Utils.base64encode(os.toByteArray())); - ////fullEnrollmentReq.print(ps); // no header/trailer - } - - asciiBASE64Blob = bs.toString(); } catch (Exception e) { e.printStackTrace(); System.exit(1); } - return asciiBASE64Blob; + + return fullEnrollmentReq; } } diff --git a/base/server/cms/src/com/netscape/cms/authentication/CMCAuth.java b/base/server/cms/src/com/netscape/cms/authentication/CMCAuth.java index b8983531a0b..94411671bf7 100644 --- a/base/server/cms/src/com/netscape/cms/authentication/CMCAuth.java +++ b/base/server/cms/src/com/netscape/cms/authentication/CMCAuth.java @@ -237,6 +237,9 @@ public void init(String name, String implName, IConfigStore config) */ public IAuthToken authenticate(IAuthCredentials authCred) throws EMissingCredential, EInvalidCredentials, EBaseException { + String method = "CMCAuth: authenticate: "; + String msg = ""; + String auditMessage = null; String auditSubjectID = auditSubjectID(); String auditReqType = ILogger.UNIDENTIFIED; @@ -261,7 +264,7 @@ public IAuthToken authenticate(IAuthCredentials authCred) throws EMissingCredent } String cmc = (String) returnVal; if (cmc == null) { - CMS.debug("CMCAuth: Authentication failed. Missing CMC."); + CMS.debug(method + "Authentication failed. Missing CMC."); // store a message in the signed audit log file auditMessage = CMS.getLogMessage( @@ -279,8 +282,9 @@ public IAuthToken authenticate(IAuthCredentials authCred) throws EMissingCredent } if (cmc.equals("")) { - log(ILogger.LL_FAILURE, - "cmc : attempted login with empty CMC."); + msg = "attempted login with empty CMC"; + CMS.debug(method + msg); + log(ILogger.LL_FAILURE, method + msg); // store a message in the signed audit log file auditMessage = CMS.getLogMessage( @@ -331,6 +335,7 @@ public IAuthToken authenticate(IAuthCredentials authCred) throws EMissingCredent if (!cmcReq.getContentType().equals( org.mozilla.jss.pkix.cms.ContentInfo.SIGNED_DATA) || !cmcReq.hasContent()) { + CMS.debug(method + "malformed cmc: either not ContentInfo.SIGNED_DATA or cmcReq has no content"); // store a message in the signed audit log file auditMessage = CMS.getLogMessage( AuditEvent.CMC_SIGNED_REQUEST_SIG_VERIFY, @@ -358,13 +363,13 @@ public IAuthToken authenticate(IAuthCredentials authCred) throws EMissingCredent if (checkSignerInfo) { IAuthToken agentToken = verifySignerInfo(authToken, cmcFullReq); if (agentToken == null) { - CMS.debug("CMCAuth: authenticate() agentToken null"); + CMS.debug(method + "agentToken null"); throw new EBaseException("CMCAuth: agent verifySignerInfo failure"); } userid = agentToken.getInString("userid"); uid = agentToken.getInString("cn"); } else { - CMS.debug("CMCAuth: authenticate() signerInfo verification bypassed"); + CMS.debug(method + "signerInfo verification bypassed"); } // reset value of auditSignerInfo if (uid != null) { @@ -377,6 +382,8 @@ public IAuthToken authenticate(IAuthCredentials authCred) throws EMissingCredent if (!id.equals(OBJECT_IDENTIFIER.id_cct_PKIData) || !ci.hasContent()) { + msg = "request EncapsulatedContentInfo content type not OBJECT_IDENTIFIER.id_cct_PKIData"; + CMS.debug( method + msg); // store a message in the signed audit log file auditMessage = CMS.getLogMessage( AuditEvent.CMC_SIGNED_REQUEST_SIG_VERIFY, @@ -406,6 +413,7 @@ public IAuthToken authenticate(IAuthCredentials authCred) throws EMissingCredent if (numReqs == 0) { // revocation request + CMS.debug(method + "numReqs 0, assume revocation request"); // reset value of auditReqType auditReqType = SIGNED_AUDIT_REVOCATION_REQUEST_TYPE; @@ -476,6 +484,7 @@ public IAuthToken authenticate(IAuthCredentials authCred) throws EMissingCredent } } else { // enrollment request + CMS.debug(method + "numReqs not 0, assume enrollment request"); // reset value of auditReqType auditReqType = SIGNED_AUDIT_ENROLLMENT_REQUEST_TYPE; diff --git a/base/server/cms/src/com/netscape/cms/authentication/CMCUserSignedAuth.java b/base/server/cms/src/com/netscape/cms/authentication/CMCUserSignedAuth.java index a18c25ee39c..2e4d6dccc61 100644 --- a/base/server/cms/src/com/netscape/cms/authentication/CMCUserSignedAuth.java +++ b/base/server/cms/src/com/netscape/cms/authentication/CMCUserSignedAuth.java @@ -29,9 +29,9 @@ import java.io.ByteArrayOutputStream; import java.io.IOException; import java.math.BigInteger; -import java.security.cert.CertificateExpiredException; import java.security.MessageDigest; import java.security.PublicKey; +import java.security.cert.CertificateExpiredException; import java.util.Enumeration; import java.util.Hashtable; import java.util.Locale; @@ -323,85 +323,90 @@ public IAuthToken authenticate(IAuthCredentials authCred) throws EMissingCredent byte[] cmcBlob = CMS.AtoB(asciiBASE64Blob); ByteArrayInputStream cmcBlobIn = new ByteArrayInputStream(cmcBlob); - org.mozilla.jss.pkix.cms.ContentInfo cmcReq = - (org.mozilla.jss.pkix.cms.ContentInfo) org.mozilla.jss.pkix.cms.ContentInfo + org.mozilla.jss.pkix.cms.ContentInfo cmcReq = (org.mozilla.jss.pkix.cms.ContentInfo) org.mozilla.jss.pkix.cms.ContentInfo .getTemplate().decode( cmcBlobIn); - if (!cmcReq.getContentType().equals( - org.mozilla.jss.pkix.cms.ContentInfo.SIGNED_DATA) || - !cmcReq.hasContent()) { - - cmcBlobIn.close(); - msg = "cmc rquest content type is not ContentInfo.SIGNED_DATA"; - CMS.debug(msg); - throw new EBaseException(msg); - } - - SignedData cmcFullReq = (SignedData) cmcReq.getInterpretedContent(); - String userid = ILogger.UNIDENTIFIED; String uid = ILogger.UNIDENTIFIED; - IConfigStore cmc_config = CMS.getConfigStore(); - boolean checkSignerInfo = cmc_config.getBoolean("cmc.signerInfo.verify", true); - if (checkSignerInfo) { - // selfSigned will be set in verifySignerInfo if applicable - IAuthToken userToken = verifySignerInfo(auditContext, authToken, cmcFullReq); - if (userToken == null) { - msg = "userToken null; verifySignerInfo failure"; - CMS.debug(method + msg); - throw new EBaseException(msg); - } else { - if (selfSigned) { - CMS.debug(method - + " self-signed cmc request will not have user identification info at this point."); - auditSignerInfo = "selfSigned"; + SignedData cmcFullReq = null; + OCTET_STRING content = null; + OBJECT_IDENTIFIER id = null; + org.mozilla.jss.pkix.cms.SignerInfo selfsign_signerInfo = null; + if (cmcReq.getContentType().equals( + org.mozilla.jss.pkix.cms.ContentInfo.SIGNED_DATA)) { + CMS.debug(method + "cmc request content is signed data"); + cmcFullReq = (SignedData) cmcReq.getInterpretedContent(); + + IConfigStore cmc_config = CMS.getConfigStore(); + boolean checkSignerInfo = cmc_config.getBoolean("cmc.signerInfo.verify", true); + if (checkSignerInfo) { + // selfSigned will be set in verifySignerInfo if applicable + IAuthToken userToken = verifySignerInfo(auditContext, authToken, cmcFullReq); + if (userToken == null) { + msg = "userToken null; verifySignerInfo failure"; + CMS.debug(method + msg); + throw new EBaseException(msg); } else { - CMS.debug(method + "signed with user cert"); - userid = userToken.getInString("userid"); - uid = userToken.getInString("cn"); - if (userid == null && uid == null) { - msg = " verifySignerInfo failure... missing userid and cn"; - CMS.debug(method + msg); - throw new EBaseException(msg); - } - // reset value of auditSignerInfo - if (uid != null && !uid.equals(ILogger.UNIDENTIFIED)) { - CMS.debug(method + "setting auditSignerInfo to uid:" + uid.trim()); - auditSignerInfo = uid.trim(); - auditSubjectID = uid.trim(); - authToken.set(IAuthToken.USER_ID, auditSubjectID); - } else if (userid != null && !userid.equals(ILogger.UNIDENTIFIED)) { - CMS.debug(method + "setting auditSignerInfo to userid:" + userid); - auditSignerInfo = userid.trim(); - auditSubjectID = userid.trim(); - authToken.set(IAuthToken.USER_ID, auditSubjectID); + if (selfSigned) { + CMS.debug(method + + " self-signed cmc request will not have user identification info at this point."); + auditSignerInfo = "selfSigned"; + } else { + CMS.debug(method + "signed with user cert"); + userid = userToken.getInString("userid"); + uid = userToken.getInString("cn"); + if (userid == null && uid == null) { + msg = " verifySignerInfo failure... missing userid and cn"; + CMS.debug(method + msg); + throw new EBaseException(msg); + } + // reset value of auditSignerInfo + if (uid != null && !uid.equals(ILogger.UNIDENTIFIED)) { + CMS.debug(method + "setting auditSignerInfo to uid:" + uid.trim()); + auditSignerInfo = uid.trim(); + auditSubjectID = uid.trim(); + authToken.set(IAuthToken.USER_ID, auditSubjectID); + } else if (userid != null && !userid.equals(ILogger.UNIDENTIFIED)) { + CMS.debug(method + "setting auditSignerInfo to userid:" + userid); + auditSignerInfo = userid.trim(); + auditSubjectID = userid.trim(); + authToken.set(IAuthToken.USER_ID, auditSubjectID); + } } } + } else { + CMS.debug(method + " signerInfo verification bypassed"); } - } else { - CMS.debug(method + " signerInfo verification bypassed"); - } - EncapsulatedContentInfo ci = cmcFullReq.getContentInfo(); - SET sis = cmcFullReq.getSignerInfos(); - // only one SignerInfo for selfSigned - org.mozilla.jss.pkix.cms.SignerInfo selfsign_signerInfo = - (org.mozilla.jss.pkix.cms.SignerInfo) sis.elementAt(0); + EncapsulatedContentInfo ci = cmcFullReq.getContentInfo(); + SET sis = cmcFullReq.getSignerInfos(); + // only one SignerInfo for selfSigned + selfsign_signerInfo = (org.mozilla.jss.pkix.cms.SignerInfo) sis.elementAt(0); - OBJECT_IDENTIFIER id = ci.getContentType(); + id = ci.getContentType(); - if (!id.equals(OBJECT_IDENTIFIER.id_cct_PKIData) || - !ci.hasContent()) { - msg = "request EncapsulatedContentInfo content type not OBJECT_IDENTIFIER.id_cct_PKIData"; - CMS.debug(method + msg); + if (!id.equals(OBJECT_IDENTIFIER.id_cct_PKIData) || + !ci.hasContent()) { + msg = "request EncapsulatedContentInfo content type not OBJECT_IDENTIFIER.id_cct_PKIData"; + CMS.debug(method + msg); + + throw new EBaseException(msg); + } + content = ci.getContent(); + } else if (cmcReq.getContentType().equals( //unsigned + org.mozilla.jss.pkix.cms.ContentInfo.DATA)) { + CMS.debug(method + "cmc request content is unsigned data...verifySignerInfo will not be called;"); + content = (OCTET_STRING) cmcReq.getInterpretedContent(); + } else { + cmcBlobIn.close(); + msg = "unsupported cmc rquest content type; must be either ContentInfo.SIGNED_DATA or ContentInfo.DATA;"; + CMS.debug(msg); throw new EBaseException(msg); } - OCTET_STRING content = ci.getContent(); - ByteArrayInputStream s = new ByteArrayInputStream(content.toByteArray()); PKIData pkiData = (PKIData) (new PKIData.Template()).decode(s); @@ -426,7 +431,8 @@ public IAuthToken authenticate(IAuthCredentials authCred) throws EMissingCredent if (type.equals( OBJECT_IDENTIFIER.id_cmc_revokeRequest)) { - /* TODO: user-signed revocation to be handled in next ticket + //further checks and actual revocation happen in CMCOutputTemplate + // if( i ==1 ) { // taggedAttribute.getType() == // OBJECT_IDENTIFIER.id_cmc_revokeRequest @@ -440,25 +446,23 @@ public IAuthToken authenticate(IAuthCredentials authCred) throws EMissingCredent for (int j = 0; j < numVals; j++) { // serialNumber INTEGER - // SEQUENCE RevRequest = (SEQUENCE) + // SEQUENCE RevokeRequest = (SEQUENCE) // values.elementAt(j); byte[] encoded = ASN1Util.encode( values.elementAt(j)); - org.mozilla.jss.asn1.ASN1Template template = new - org.mozilla.jss.pkix.cmmf.RevRequest.Template(); - org.mozilla.jss.pkix.cmmf.RevRequest revRequest = - (org.mozilla.jss.pkix.cmmf.RevRequest) - ASN1Util.decode(template, encoded); + org.mozilla.jss.asn1.ASN1Template template = new org.mozilla.jss.pkix.cmc.RevokeRequest.Template(); + org.mozilla.jss.pkix.cmc.RevokeRequest revRequest = (org.mozilla.jss.pkix.cmc.RevokeRequest) ASN1Util + .decode(template, encoded); - // SEQUENCE RevRequest = (SEQUENCE) + // SEQUENCE RevokeRequest = (SEQUENCE) // ASN1Util.decode( // SEQUENCE.getTemplate(), // ASN1Util.encode( // values.elementAt(j))); - // SEQUENCE RevRequest = + // SEQUENCE RevokeRequest = // values.elementAt(j); - // int revReqSize = RevRequest.size(); + // int revReqSize = RevokeRequest.size(); // if( revReqSize > 3 ) { // INTEGER serialNumber = // new INTEGER((long)0); @@ -473,13 +477,10 @@ public IAuthToken authenticate(IAuthCredentials authCred) throws EMissingCredent Integer IntObject = Integer.valueOf((int) reasonCode); authToken.set(REASON_CODE, IntObject); - //authToken.set("uid", uid); //authToken.set("userid", userid); } - */ - } } @@ -648,8 +649,7 @@ public IAuthToken authenticate(IAuthCredentials authCred) throws EMissingCredent certInfoArray[i] = certInfo; if (selfSigned) { - selfsign_skiExtn = - (SubjectKeyIdentifierExtension) CryptoUtil + selfsign_skiExtn = (SubjectKeyIdentifierExtension) CryptoUtil .getExtensionFromCertTemplate(template, PKIXExtensions.SubjectKey_Id); if (selfsign_skiExtn != null) { CMS.debug(method + @@ -702,16 +702,24 @@ public IAuthToken authenticate(IAuthCredentials authCred) throws EMissingCredent throw new EInvalidCredentials(e.toString()); } - // store a message in the signed audit log file - auditMessage = CMS.getLogMessage( - AuditEvent.CMC_USER_SIGNED_REQUEST_SIG_VERIFY_SUCCESS, - auditSubjectID, - ILogger.SUCCESS, - auditReqType, - auditCertSubject, - auditSignerInfo); - - audit(auditMessage); + // For accuracy, make sure revocation by shared secret doesn't + // log CMC_USER_SIGNED_REQUEST_SIG_VERIFY_SUCCESS + if (authToken.get(IAuthManager.CRED_CMC_SIGNING_CERT) != null || + authToken.get(IAuthManager.CRED_CMC_SELF_SIGNED) != null) { + // store a message in the signed audit log file + auditMessage = CMS.getLogMessage( + AuditEvent.CMC_USER_SIGNED_REQUEST_SIG_VERIFY_SUCCESS, + auditSubjectID, + ILogger.SUCCESS, + auditReqType, + auditCertSubject, + auditSignerInfo); + + audit(auditMessage); + } else { + CMS.debug(method + + "audit event CMC_USER_SIGNED_REQUEST_SIG_VERIFY_SUCCESS not logged due to unsigned data for revocation with shared secret."); + } CMS.debug(method + "ends successfully; returning authToken"); return authToken; @@ -1029,10 +1037,15 @@ protected IAuthToken verifySignerInfo( } else { CMS.debug(method + "found signing cert... verifying"); - //capture auditSubjectID first in case of failure - netscape.security.x509.X500Name tempPrincipal = + // capture auditSubjectID first in case of failure + netscape.security.x509.X500Name principal = (X500Name) x509Certs[0].getSubjectDN(); - CN = tempPrincipal.getCommonName(); //tempToken.get("userid"); + + // capture signer principal to be checked against + // cert subject principal later in CMCOutputTemplate + // in case of user signed revocation + auditContext.put(SessionContext.CMC_SIGNER_PRINCIPAL, principal); + CN = principal.getCommonName(); //tempToken.get("userid"); CMS.debug(method + " Principal name = " + CN); auditContext.put(SessionContext.USER_ID, CN); @@ -1093,15 +1106,18 @@ protected IAuthToken verifySignerInfo( // now check revocation status of the cert if (CMS.isRevoked(x509Certs)) { CMS.debug(method + "CMC signing cert is a revoked certificate"); + s.close(); throw new EInvalidCredentials(CMS.getUserMessage("CMS_AUTHENTICATION_INVALID_CREDENTIAL")); } try { //do this again anyways cert.checkValidity(); } catch (CertificateExpiredException e) { CMS.debug(method + "CMC signing cert is an expired certificate"); + s.close(); throw new EInvalidCredentials(CMS.getUserMessage("CMS_AUTHENTICATION_INVALID_CREDENTIAL")); } catch (Exception e) { CMS.debug(method + e.toString()); + s.close(); throw new EInvalidCredentials(CMS.getUserMessage("CMS_AUTHENTICATION_INVALID_CREDENTIAL")); } 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 2591acefafc..74da8e75f13 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 @@ -588,16 +588,25 @@ public PKIData getPKIDataFromCMCblob(Locale locale, String certReqBlob) try { byte data[] = CMS.AtoB(creq); ByteArrayInputStream cmcBlobIn = new ByteArrayInputStream(data); + PKIData pkiData = null; org.mozilla.jss.pkix.cms.ContentInfo cmcReq = (org.mozilla.jss.pkix.cms.ContentInfo) org.mozilla.jss.pkix.cms.ContentInfo .getTemplate().decode(cmcBlobIn); - org.mozilla.jss.pkix.cms.SignedData cmcFullReq = (org.mozilla.jss.pkix.cms.SignedData) cmcReq - .getInterpretedContent(); - org.mozilla.jss.pkix.cms.EncapsulatedContentInfo ci = cmcFullReq.getContentInfo(); - OCTET_STRING content = ci.getContent(); - + OCTET_STRING content = null; + if (cmcReq.getContentType().equals( + org.mozilla.jss.pkix.cms.ContentInfo.SIGNED_DATA)) { + CMS.debug(method + "cmc request content is signed data"); + org.mozilla.jss.pkix.cms.SignedData cmcFullReq = (org.mozilla.jss.pkix.cms.SignedData) cmcReq + .getInterpretedContent(); + org.mozilla.jss.pkix.cms.EncapsulatedContentInfo ci = cmcFullReq.getContentInfo(); + content = ci.getContent(); + + } else { // for unsigned revocation requests (using shared secret) + CMS.debug(method + "cmc request content is unsigned data"); + content = (OCTET_STRING) cmcReq.getInterpretedContent(); + } ByteArrayInputStream s = new ByteArrayInputStream(content.toByteArray()); - PKIData pkiData = (PKIData) (new PKIData.Template()).decode(s); + pkiData = (PKIData) (new PKIData.Template()).decode(s); mCMCData = pkiData; //PKIData pkiData = (PKIData) @@ -708,6 +717,8 @@ public TaggedRequest[] parseCMC(Locale locale, String certreq, boolean donePOI) byte randomSeed[] = null; UTF8String ident_s = null; SessionContext context = SessionContext.getContext(); + + boolean id_cmc_revokeRequest = false; if (!context.containsKey("numOfControls")) { CMS.debug(method + "numcontrols="+ numcontrols); if (numcontrols > 0) { @@ -735,7 +746,13 @@ public TaggedRequest[] parseCMC(Locale locale, String certreq, boolean donePOI) for (int i = 0; i < numcontrols; i++) { attributes[i] = (TaggedAttribute) controlSeq.elementAt(i); OBJECT_IDENTIFIER oid = attributes[i].getType(); - if (oid.equals(OBJECT_IDENTIFIER.id_cmc_decryptedPOP)) { + if (oid.equals(OBJECT_IDENTIFIER.id_cmc_revokeRequest)) { + id_cmc_revokeRequest = true; + // put in context for processing in + // CMCOutputTemplate.java later + context.put(OBJECT_IDENTIFIER.id_cmc_revokeRequest, + attributes[i]); + } else if (oid.equals(OBJECT_IDENTIFIER.id_cmc_decryptedPOP)) { CMS.debug(method + " id_cmc_decryptedPOP found"); id_cmc_decryptedPOP = true; decPopVals = attributes[i].getValues(); @@ -766,6 +783,10 @@ public TaggedRequest[] parseCMC(Locale locale, String certreq, boolean donePOI) */ CMS.debug(method + "processing controls..."); + if (id_cmc_revokeRequest) { + CMS.debug(method + "revocation control"); + } + if (id_cmc_identification) { if (ident == null) { msg = "id_cmc_identification contains null attribute value"; @@ -801,7 +822,7 @@ public TaggedRequest[] parseCMC(Locale locale, String certreq, boolean donePOI) // checking Proof Of Identity, if not pre-signed - if (donePOI) { + if (donePOI || id_cmc_revokeRequest) { // for logging purposes if (id_cmc_identityProofV2) { CMS.debug(method @@ -921,6 +942,7 @@ public TaggedRequest[] parseCMC(Locale locale, String certreq, boolean donePOI) SEQUENCE otherMsgSeq = pkiData.getOtherMsgSequence(); int numOtherMsgs = otherMsgSeq.size(); if (!context.containsKey("numOfOtherMsgs")) { + CMS.debug(method + "found numOfOtherMsgs: " + numOtherMsgs); context.put("numOfOtherMsgs", Integer.valueOf(numOtherMsgs)); for (int i = 0; i < numOtherMsgs; i++) { OtherMsg omsg = (OtherMsg) (ASN1Util.decode(OtherMsg.getTemplate(), @@ -959,6 +981,8 @@ public TaggedRequest[] parseCMC(Locale locale, String certreq, boolean donePOI) boolean valid = true; for (int i = 0; i < nummsgs; i++) { msgs[i] = (TaggedRequest) reqSeq.elementAt(i); + if (id_cmc_revokeRequest) + continue; if (popLinkWitnessRequired && !context.containsKey("POPLinkWitnessV2") && !context.containsKey("POPLinkWitness")) { @@ -1271,7 +1295,7 @@ private boolean verifyPOPLinkWitness( boolean sharedSecretFound = true; String configName = "cmc.sharedSecret.class"; String sharedSecret = null; - ISharedToken tokenClass = getSharedTokenClass(configName); + ISharedToken tokenClass = CMS.getSharedTokenClass(configName); if (tokenClass == null) { CMS.debug(method + " Failed to retrieve shared secret plugin class"); sharedSecretFound = false; @@ -1498,40 +1522,6 @@ private SEQUENCE getRequestBpids(SEQUENCE reqSeq) { 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 * @@ -1577,7 +1567,7 @@ private boolean verifyIdentityProofV2( } String configName = "cmc.sharedSecret.class"; - ISharedToken tokenClass = getSharedTokenClass(configName); + ISharedToken tokenClass = CMS.getSharedTokenClass(configName); if (tokenClass == null) { msg = " Failed to retrieve shared secret plugin class"; @@ -1681,7 +1671,7 @@ private boolean verifyIdentityProof( return false; String configName = "cmc.sharedSecret.class"; - ISharedToken tokenClass = getSharedTokenClass(configName); + ISharedToken tokenClass = CMS.getSharedTokenClass(configName); if (tokenClass == null) { CMS.debug(method + " Failed to retrieve shared secret plugin class"); return false; diff --git a/base/server/cms/src/com/netscape/cms/servlet/cert/CMCRevReqServlet.java b/base/server/cms/src/com/netscape/cms/servlet/cert/CMCRevReqServlet.java index 24ba4947305..a66cd957471 100644 --- a/base/server/cms/src/com/netscape/cms/servlet/cert/CMCRevReqServlet.java +++ b/base/server/cms/src/com/netscape/cms/servlet/cert/CMCRevReqServlet.java @@ -142,6 +142,8 @@ public void init(ServletConfig sc) throws ServletException { * @param cmsReq the object holding the request and response information */ protected void process(CMSRequest cmsReq) throws EBaseException { + String method = "CMCRevReqServlet: process: "; + CMS.debug(method + "begins"); String cmcAgentSerialNumber = null; IArgBlock httpParams = cmsReq.getHttpParams(); @@ -151,7 +153,7 @@ protected void process(CMSRequest cmsReq) throws EBaseException { CMSTemplate form = null; Locale[] locale = new Locale[1]; - CMS.debug("**** mFormPath = " + mFormPath); + CMS.debug(method + "**** mFormPath = " + mFormPath); try { form = getTemplate(mFormPath, req, locale); } catch (IOException e) { diff --git a/base/server/cms/src/com/netscape/cms/servlet/cert/ListCerts.java b/base/server/cms/src/com/netscape/cms/servlet/cert/ListCerts.java index 3794f109f41..01c4b6aca68 100644 --- a/base/server/cms/src/com/netscape/cms/servlet/cert/ListCerts.java +++ b/base/server/cms/src/com/netscape/cms/servlet/cert/ListCerts.java @@ -461,11 +461,11 @@ private void processCertFilter( ICertRecord rec = e.nextElement(); if (rec == null) { - CMS.debug("ListCerts: * record " + count + " is null"); + //CMS.debug("ListCerts: * record " + count + " is null"); break; } curSerial = rec.getSerialNumber(); - CMS.debug("ListCerts: * record " + count + ": " + curSerial); + //CMS.debug("ListCerts: * record " + count + ": " + curSerial); if (count == 0) { firstSerial = curSerial; @@ -493,11 +493,11 @@ private void processCertFilter( } if (mReverse) { - CMS.debug("ListCerts: returning with rcount: " + rcount); + //CMS.debug("ListCerts: returning with rcount: " + rcount); recs[rcount++] = rec; } else { - CMS.debug("ListCerts: returning with arg block"); + //CMS.debug("ListCerts: returning with arg block"); IArgBlock rarg = CMS.createArgBlock(); fillRecordIntoArg(rec, rarg); argSet.addRepeatRecord(rarg); @@ -514,7 +514,7 @@ private void processCertFilter( CMS.debug("ListCerts: fill records into arg block and argSet"); for (int ii = rcount - 1; ii >= 0; ii--) { if (recs[ii] != null) { - CMS.debug("ListCerts: processing recs[" + ii + "]"); + //CMS.debug("ListCerts: processing recs[" + ii + "]"); IArgBlock rarg = CMS.createArgBlock(); // CMS.debug("item " + ii + " is serial #" + recs[ii].getSerialNumber()); fillRecordIntoArg(recs[ii], rarg); 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 8d6c37f2c05..067dce76b25 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 @@ -25,6 +25,7 @@ import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.security.PublicKey; +import java.security.cert.CertificateExpiredException; import java.util.Date; import java.util.Hashtable; @@ -55,9 +56,9 @@ import org.mozilla.jss.pkix.cmc.OtherMsg; import org.mozilla.jss.pkix.cmc.PendInfo; import org.mozilla.jss.pkix.cmc.ResponseBody; +import org.mozilla.jss.pkix.cmc.RevokeRequest; import org.mozilla.jss.pkix.cmc.TaggedAttribute; import org.mozilla.jss.pkix.cmc.TaggedRequest; -import org.mozilla.jss.pkix.cmmf.RevRequest; import org.mozilla.jss.pkix.cms.ContentInfo; import org.mozilla.jss.pkix.cms.EncapsulatedContentInfo; import org.mozilla.jss.pkix.cms.EnvelopedData; @@ -76,8 +77,10 @@ import com.netscape.certsrv.ca.ICertificateAuthority; import com.netscape.certsrv.dbs.certdb.ICertRecord; import com.netscape.certsrv.dbs.certdb.ICertificateRepository; +import com.netscape.certsrv.logging.AuditEvent; import com.netscape.certsrv.logging.AuditFormat; import com.netscape.certsrv.logging.ILogger; +import com.netscape.certsrv.logging.event.CertStatusChangeRequestProcessedEvent; import com.netscape.certsrv.profile.IEnrollProfile; import com.netscape.certsrv.request.IRequest; import com.netscape.certsrv.request.IRequestQueue; @@ -101,6 +104,8 @@ * @version $ $, $Date$ */ public class CMCOutputTemplate { + protected ILogger mSignedAuditLogger = CMS.getSignedAuditLogger(); + public CMCOutputTemplate() { } @@ -212,14 +217,12 @@ public void createFullResponse(HttpServletResponse resp, IRequest[] reqs, } } } else { - CMS.debug(method + " reqs null. why?"); + CMS.debug(method + " reqs null. could be revocation"); } TaggedAttribute tagattr = null; CMCStatusInfo cmcStatusInfo = null; -//cfu - SEQUENCE decryptedPOPBpids = (SEQUENCE) context.get("decryptedPOP"); if (decryptedPOPBpids != null && decryptedPOPBpids.size() > 0) { OtherInfo otherInfo = new OtherInfo(OtherInfo.FAIL, @@ -880,8 +883,8 @@ private int processSenderNonceControl(TaggedAttribute attr, String salt = "lala123" + date.toString(); byte[] dig; try { - MessageDigest SHA1Digest = MessageDigest.getInstance("SHA1"); - dig = SHA1Digest.digest(salt.getBytes()); + MessageDigest SHA2Digest = MessageDigest.getInstance("SHA256"); + dig = SHA2Digest.digest(salt.getBytes()); } catch (NoSuchAlgorithmException ex) { dig = salt.getBytes(); } @@ -920,22 +923,59 @@ private int processDataReturnControl(TaggedAttribute attr, private int processRevokeRequestControl(TaggedAttribute attr, SEQUENCE controlSeq, int bpid) throws InvalidBERException, EBaseException, IOException { + String method = "CMCOutputTemplate: processRevokeRequestControl: "; + String msg = ""; + CMS.debug(method + "begins"); boolean revoke = false; SessionContext context = SessionContext.getContext(); + String authManagerId = (String) context.get(SessionContext.AUTH_MANAGER_ID); + if (authManagerId == null) { + CMS.debug(method + "authManagerId null.????"); + //unlikely, but... + authManagerId = "none"; + } else { + CMS.debug(method + "authManagerId =" + authManagerId); + } + + // in case of CMCUserSignedAuth, + // for matching signer and revoked cert principal + X500Name signerPrincipal = null; + + // for auditing + String auditRequesterID = null; + auditRequesterID = (String) context.get(SessionContext.USER_ID); + + if (auditRequesterID != null) { + auditRequesterID = auditRequesterID.trim(); + } else { + auditRequesterID = ILogger.NONROLEUSER; + } + signerPrincipal = (X500Name) context.get(SessionContext.CMC_SIGNER_PRINCIPAL); + String auditSubjectID = null; + String auditRequestType = "revoke"; + String auditSerialNumber = null; + String auditReasonNum = null; + RequestStatus auditApprovalStatus = RequestStatus.REJECTED; + if (attr != null) { INTEGER attrbpid = attr.getBodyPartID(); CMCStatusInfo cmcStatusInfo = null; SET vals = attr.getValues(); if (vals.size() > 0) { - RevRequest revRequest = - (RevRequest) (ASN1Util.decode(new RevRequest.Template(), - ASN1Util.encode(vals.elementAt(0)))); - OCTET_STRING str = revRequest.getSharedSecret(); + RevokeRequest revRequest = (RevokeRequest) (ASN1Util.decode(new RevokeRequest.Template(), + ASN1Util.encode(vals.elementAt(0)))); + OCTET_STRING reqSecret = revRequest.getSharedSecret(); INTEGER pid = attr.getBodyPartID(); TaggedAttribute tagattr = null; INTEGER revokeCertSerial = revRequest.getSerialNumber(); + ENUMERATED n = revRequest.getReason(); + RevocationReason reason = toRevocationReason(n); + auditReasonNum = reason.toString(); BigInteger revokeSerial = new BigInteger(revokeCertSerial.toByteArray()); - if (str == null) { + auditSerialNumber = revokeSerial.toString(); + + if (reqSecret == null) { + CMS.debug(method + "no shared secret in request; Checking signature;"); boolean needVerify = true; try { needVerify = CMS.getConfigStore().getBoolean("cmc.revokeCert.verify", true); @@ -943,67 +983,75 @@ private int processRevokeRequestControl(TaggedAttribute attr, } if (needVerify) { - Integer num1 = (Integer) context.get("numOfOtherMsgs"); - int num = num1.intValue(); - for (int i = 0; i < num; i++) { - OtherMsg data = (OtherMsg) context.get("otherMsg" + i); - INTEGER dpid = data.getBodyPartID(); - if (pid.longValue() == dpid.longValue()) { - ANY msgValue = data.getOtherMsgValue(); - SignedData msgData = - (SignedData) msgValue.decodeWith(SignedData.getTemplate()); - if (!verifyRevRequestSignature(msgData)) { - OtherInfo otherInfo = - new OtherInfo(OtherInfo.FAIL, new INTEGER(OtherInfo.BAD_MESSAGE_CHECK), - null); - SEQUENCE failed_bpids = new SEQUENCE(); - failed_bpids.addElement(attrbpid); - cmcStatusInfo = - new CMCStatusInfo(CMCStatusInfo.FAILED, failed_bpids, (String) null, - otherInfo); - tagattr = new TaggedAttribute( - new INTEGER(bpid++), - OBJECT_IDENTIFIER.id_cmc_cMCStatusInfo, cmcStatusInfo); - controlSeq.addElement(tagattr); - return bpid; + if (authManagerId.equals("CMCUserSignedAuth")) { + if (signerPrincipal == null) { + CMS.debug(method + "missing CMC signer principal"); + OtherInfo otherInfo = new OtherInfo(OtherInfo.FAIL, + new INTEGER(OtherInfo.BAD_MESSAGE_CHECK), + null); + SEQUENCE failed_bpids = new SEQUENCE(); + failed_bpids.addElement(attrbpid); + cmcStatusInfo = new CMCStatusInfo(CMCStatusInfo.FAILED, failed_bpids, (String) null, + otherInfo); + tagattr = new TaggedAttribute( + new INTEGER(bpid++), + OBJECT_IDENTIFIER.id_cmc_cMCStatusInfo, cmcStatusInfo); + controlSeq.addElement(tagattr); + return bpid; + } + } else { // !CMCUserSignedAuth + + // this code is making the assumption that OtherMsg + // is used for signer info in signed cmc revocation, + // when in fact the signer info is + // in the outer layer and should have already been + // verified in the auth manager; + // Left here for possible legacy client(s) + + Integer num1 = (Integer) context.get("numOfOtherMsgs"); + CMS.debug(method + "found numOfOtherMsgs =" + num1.toString()); + int num = num1.intValue(); + for (int i = 0; i < num; i++) { + OtherMsg data = (OtherMsg) context.get("otherMsg" + i); + INTEGER dpid = data.getBodyPartID(); + if (pid.longValue() == dpid.longValue()) { + CMS.debug(method + "body part id match;"); + ANY msgValue = data.getOtherMsgValue(); + SignedData msgData = (SignedData) msgValue.decodeWith(SignedData.getTemplate()); + if (!verifyRevRequestSignature(msgData)) { + OtherInfo otherInfo = new OtherInfo(OtherInfo.FAIL, + new INTEGER(OtherInfo.BAD_MESSAGE_CHECK), + null); + SEQUENCE failed_bpids = new SEQUENCE(); + failed_bpids.addElement(attrbpid); + cmcStatusInfo = new CMCStatusInfo(CMCStatusInfo.FAILED, failed_bpids, + (String) null, + otherInfo); + tagattr = new TaggedAttribute( + new INTEGER(bpid++), + OBJECT_IDENTIFIER.id_cmc_cMCStatusInfo, cmcStatusInfo); + controlSeq.addElement(tagattr); + return bpid; + } + } else { + CMS.debug(method + "body part id do not match;"); } } } } revoke = true; + } else { //use shared secret; request unsigned + CMS.debug(method + "checking shared secret"); // check shared secret - } else { - ISharedToken tokenClass = null; - boolean sharedSecretFound = true; - String name = null; - try { - name = CMS.getConfigStore().getString("cmc.revokeCert.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; - } - - 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); - sharedSecretFound = false; - } - - if (!sharedSecretFound) { - CMS.debug("CMCOutputTemplate: class for shared secret was not found."); - OtherInfo otherInfo = - new OtherInfo(OtherInfo.FAIL, new INTEGER(OtherInfo.INTERNAL_CA_ERROR), null); + //TODO: remember to provide one-time-use when working + // on shared token + ISharedToken tokenClass = + CMS.getSharedTokenClass("cmc.revokeCert.sharedSecret.class"); + if (tokenClass == null) { + CMS.debug(method + " Failed to retrieve shared secret plugin class"); + OtherInfo otherInfo = new OtherInfo(OtherInfo.FAIL, new INTEGER(OtherInfo.INTERNAL_CA_ERROR), + null); SEQUENCE failed_bpids = new SEQUENCE(); failed_bpids.addElement(attrbpid); cmcStatusInfo = new CMCStatusInfo(CMCStatusInfo.FAILED, failed_bpids, (String) null, otherInfo); @@ -1014,15 +1062,13 @@ private int processRevokeRequestControl(TaggedAttribute attr, return bpid; } - String sharedSecret = null; - if (tokenClass != null) { - sharedSecret = tokenClass.getSharedToken(revokeSerial); - } + String sharedSecret = + sharedSecret = tokenClass.getSharedToken(revokeSerial); if (sharedSecret == null) { - CMS.debug("CMCOutputTemplate: class for shared secret was not found."); - OtherInfo otherInfo = - new OtherInfo(OtherInfo.FAIL, new INTEGER(OtherInfo.INTERNAL_CA_ERROR), null); + CMS.debug("CMCOutputTemplate: shared secret not found."); + OtherInfo otherInfo = new OtherInfo(OtherInfo.FAIL, new INTEGER(OtherInfo.INTERNAL_CA_ERROR), + null); SEQUENCE failed_bpids = new SEQUENCE(); failed_bpids.addElement(attrbpid); cmcStatusInfo = new CMCStatusInfo(CMCStatusInfo.FAILED, failed_bpids, (String) null, otherInfo); @@ -1033,15 +1079,17 @@ private int processRevokeRequestControl(TaggedAttribute attr, return bpid; } - byte[] strb = str.toByteArray(); - String clientSC = new String(strb); + byte[] reqSecretb = reqSecret.toByteArray(); + String clientSC = new String(reqSecretb); if (clientSC.equals(sharedSecret)) { - CMS.debug("CMCOutputTemplate: Both client and server shared secret are the same, can go ahead to revoke certificate."); + CMS.debug(method + + " Client and server shared secret are the same, can go ahead and revoke certificate."); revoke = true; } else { - CMS.debug("CMCOutputTemplate: Both client and server shared secret are not the same, cant revoke certificate."); - OtherInfo otherInfo = - new OtherInfo(OtherInfo.FAIL, new INTEGER(OtherInfo.BAD_MESSAGE_CHECK), null); + CMS.debug(method + + " Client and server shared secret are not the same, cannot revoke certificate."); + OtherInfo otherInfo = new OtherInfo(OtherInfo.FAIL, new INTEGER(OtherInfo.BAD_MESSAGE_CHECK), + null); SEQUENCE failed_bpids = new SEQUENCE(); failed_bpids.addElement(attrbpid); cmcStatusInfo = new CMCStatusInfo(CMCStatusInfo.FAILED, failed_bpids, (String) null, otherInfo); @@ -1049,6 +1097,16 @@ private int processRevokeRequestControl(TaggedAttribute attr, new INTEGER(bpid++), OBJECT_IDENTIFIER.id_cmc_cMCStatusInfo, cmcStatusInfo); controlSeq.addElement(tagattr); + + audit(new CertStatusChangeRequestProcessedEvent( + auditSubjectID, + ILogger.FAILURE, + auditRequesterID, + auditSerialNumber, + auditRequestType, + auditReasonNum, + auditApprovalStatus)); + return bpid; } } @@ -1060,11 +1118,11 @@ private int processRevokeRequestControl(TaggedAttribute attr, try { record = repository.readCertificateRecord(revokeSerial); } catch (EBaseException ee) { - CMS.debug("CMCOutputTemplate: Exception: " + ee.toString()); + CMS.debug(method + "Exception: " + ee.toString()); } if (record == null) { - CMS.debug("CMCOutputTemplate: The certificate is not found"); + CMS.debug(method + " The certificate is not found"); OtherInfo otherInfo = new OtherInfo(OtherInfo.FAIL, new INTEGER(OtherInfo.BAD_CERT_ID), null); SEQUENCE failed_bpids = new SEQUENCE(); failed_bpids.addElement(attrbpid); @@ -1088,11 +1146,46 @@ record = repository.readCertificateRecord(revokeSerial); controlSeq.addElement(tagattr); return bpid; } + X509CertImpl impl = record.getCertificate(); + + X500Name certPrincipal = (X500Name) impl.getSubjectDN(); + auditSubjectID = certPrincipal.getCommonName(); + + // in case of user-signed request, check if signer + // principal matches that of the revoking cert + if ((reqSecret == null) && authManagerId.equals("CMCUserSignedAuth")) { + if (!certPrincipal.equals(signerPrincipal)) { + msg = "certificate principal and signer do not match"; + CMS.debug(method + msg); + OtherInfo otherInfo = new OtherInfo(OtherInfo.FAIL, new INTEGER(OtherInfo.BAD_IDENTITY), + null); + SEQUENCE failed_bpids = new SEQUENCE(); + failed_bpids.addElement(attrbpid); + cmcStatusInfo = new CMCStatusInfo(CMCStatusInfo.FAILED, failed_bpids, msg, + otherInfo); + tagattr = new TaggedAttribute( + new INTEGER(bpid++), + OBJECT_IDENTIFIER.id_cmc_cMCStatusInfo, cmcStatusInfo); + controlSeq.addElement(tagattr); + + audit(new CertStatusChangeRequestProcessedEvent( + auditSubjectID, + ILogger.FAILURE, + auditRequesterID, + auditSerialNumber, + auditRequestType, + auditReasonNum, + auditApprovalStatus)); + + return bpid; + } else { + CMS.debug(method + "certificate principal and signer match"); + } + } + X509CertImpl[] impls = new X509CertImpl[1]; impls[0] = impl; - ENUMERATED n = revRequest.getReason(); - RevocationReason reason = toRevocationReason(n); CRLReasonExtension crlReasonExtn = new CRLReasonExtension(reason); CRLExtensions entryExtn = new CRLExtensions(); GeneralizedTime t = revRequest.getInvalidityDate(); @@ -1105,8 +1198,8 @@ record = repository.readCertificateRecord(revokeSerial); entryExtn.set(crlReasonExtn.getName(), crlReasonExtn); } - RevokedCertImpl revCertImpl = - new RevokedCertImpl(impl.getSerialNumber(), CMS.getCurrentDate(), entryExtn); + RevokedCertImpl revCertImpl = new RevokedCertImpl(impl.getSerialNumber(), CMS.getCurrentDate(), + entryExtn); RevokedCertImpl[] revCertImpls = new RevokedCertImpl[1]; revCertImpls[0] = revCertImpl; IRequestQueue queue = ca.getRequestQueue(); @@ -1122,20 +1215,30 @@ record = repository.readCertificateRecord(revokeSerial); RequestStatus stat = revReq.getRequestStatus(); if (stat == RequestStatus.COMPLETE) { Integer result = revReq.getExtDataInInteger(IRequest.RESULT); - CMS.debug("CMCOutputTemplate: revReq result = " + result); + CMS.debug(method + " revReq result = " + result); if (result.equals(IRequest.RES_ERROR)) { CMS.debug("CMCOutputTemplate: revReq exception: " + revReq.getExtDataInString(IRequest.ERROR)); - OtherInfo otherInfo = - new OtherInfo(OtherInfo.FAIL, new INTEGER(OtherInfo.BAD_REQUEST), null); + OtherInfo otherInfo = new OtherInfo(OtherInfo.FAIL, new INTEGER(OtherInfo.BAD_REQUEST), + null); SEQUENCE failed_bpids = new SEQUENCE(); failed_bpids.addElement(attrbpid); - cmcStatusInfo = - new CMCStatusInfo(CMCStatusInfo.FAILED, failed_bpids, (String) null, otherInfo); + cmcStatusInfo = new CMCStatusInfo(CMCStatusInfo.FAILED, failed_bpids, (String) null, + otherInfo); tagattr = new TaggedAttribute( new INTEGER(bpid++), OBJECT_IDENTIFIER.id_cmc_cMCStatusInfo, cmcStatusInfo); controlSeq.addElement(tagattr); + + audit(new CertStatusChangeRequestProcessedEvent( + auditSubjectID, + ILogger.FAILURE, + auditRequesterID, + auditSerialNumber, + auditRequestType, + auditReasonNum, + auditApprovalStatus)); + return bpid; } } @@ -1148,7 +1251,7 @@ record = repository.readCertificateRecord(revokeSerial); impl.getSubjectDN(), impl.getSerialNumber().toString(16), reason.toString() }); - CMS.debug("CMCOutputTemplate: Certificate get revoked."); + CMS.debug(method + " Certificate revoked."); SEQUENCE success_bpids = new SEQUENCE(); success_bpids.addElement(attrbpid); cmcStatusInfo = new CMCStatusInfo(CMCStatusInfo.SUCCESS, @@ -1157,6 +1260,16 @@ record = repository.readCertificateRecord(revokeSerial); new INTEGER(bpid++), OBJECT_IDENTIFIER.id_cmc_cMCStatusInfo, cmcStatusInfo); controlSeq.addElement(tagattr); + + auditApprovalStatus = RequestStatus.COMPLETE; + audit(new CertStatusChangeRequestProcessedEvent( + auditSubjectID, + ILogger.SUCCESS, + auditRequesterID, + auditSerialNumber, + auditRequestType, + auditReasonNum, + auditApprovalStatus)); return bpid; } else { OtherInfo otherInfo = new OtherInfo(OtherInfo.FAIL, new INTEGER(OtherInfo.BAD_MESSAGE_CHECK), null); @@ -1167,6 +1280,16 @@ record = repository.readCertificateRecord(revokeSerial); new INTEGER(bpid++), OBJECT_IDENTIFIER.id_cmc_cMCStatusInfo, cmcStatusInfo); controlSeq.addElement(tagattr); + + audit(new CertStatusChangeRequestProcessedEvent( + auditSubjectID, + ILogger.FAILURE, + auditRequesterID, + auditSerialNumber, + auditRequestType, + auditReasonNum, + auditApprovalStatus)); + return bpid; } } @@ -1175,54 +1298,81 @@ record = repository.readCertificateRecord(revokeSerial); return bpid; } + protected void audit(AuditEvent event) { + + String template = event.getMessage(); + Object[] params = event.getParameters(); + + String message = CMS.getLogMessage(template, params); + + audit(message); + } + + protected void audit(String msg) { + // in this case, do NOT strip preceding/trailing whitespace + // from passed-in String parameters + + if (mSignedAuditLogger == null) { + return; + } + + mSignedAuditLogger.log(ILogger.EV_SIGNED_AUDIT, + null, + ILogger.S_SIGNED_AUDIT, + ILogger.LL_SECURITY, + msg); + } + private RevocationReason toRevocationReason(ENUMERATED n) { long code = n.getValue(); - if (code == RevRequest.aACompromise.getValue()) + if (code == RevokeRequest.aACompromise.getValue()) return RevocationReason.UNSPECIFIED; - else if (code == RevRequest.affiliationChanged.getValue()) + else if (code == RevokeRequest.affiliationChanged.getValue()) return RevocationReason.AFFILIATION_CHANGED; - else if (code == RevRequest.cACompromise.getValue()) + else if (code == RevokeRequest.cACompromise.getValue()) return RevocationReason.CA_COMPROMISE; - else if (code == RevRequest.certificateHold.getValue()) + else if (code == RevokeRequest.certificateHold.getValue()) return RevocationReason.CERTIFICATE_HOLD; - else if (code == RevRequest.cessationOfOperation.getValue()) + else if (code == RevokeRequest.cessationOfOperation.getValue()) return RevocationReason.CESSATION_OF_OPERATION; - else if (code == RevRequest.keyCompromise.getValue()) + else if (code == RevokeRequest.keyCompromise.getValue()) return RevocationReason.KEY_COMPROMISE; - else if (code == RevRequest.privilegeWithdrawn.getValue()) + else if (code == RevokeRequest.privilegeWithdrawn.getValue()) return RevocationReason.UNSPECIFIED; - else if (code == RevRequest.removeFromCRL.getValue()) + else if (code == RevokeRequest.removeFromCRL.getValue()) return RevocationReason.REMOVE_FROM_CRL; - else if (code == RevRequest.superseded.getValue()) + else if (code == RevokeRequest.superseded.getValue()) return RevocationReason.SUPERSEDED; - else if (code == RevRequest.unspecified.getValue()) + else if (code == RevokeRequest.unspecified.getValue()) return RevocationReason.UNSPECIFIED; return RevocationReason.UNSPECIFIED; } private boolean verifyRevRequestSignature(SignedData msgData) { + String method = "CMCOutputTemplate: verifyRevRequestSignature: "; + CMS.debug(method + "begins"); try { EncapsulatedContentInfo ci = msgData.getContentInfo(); OCTET_STRING content = ci.getContent(); ByteArrayInputStream s = new ByteArrayInputStream(content.toByteArray()); TaggedAttribute tattr = (TaggedAttribute) (new TaggedAttribute.Template()).decode(s); SET values = tattr.getValues(); - RevRequest revRequest = null; - if (values != null && values.size() > 0) - revRequest = - (RevRequest) (ASN1Util.decode(new RevRequest.Template(), - ASN1Util.encode(values.elementAt(0)))); + RevokeRequest revRequest = null; + if (values != null && values.size() > 0) { + revRequest = (RevokeRequest) (ASN1Util.decode(new RevokeRequest.Template(), + ASN1Util.encode(values.elementAt(0)))); + } else { + CMS.debug(method + "attribute null"); + return false; + } SET dias = msgData.getDigestAlgorithmIdentifiers(); int numDig = dias.size(); Hashtable digs = new Hashtable(); for (int i = 0; i < numDig; i++) { - AlgorithmIdentifier dai = - (AlgorithmIdentifier) dias.elementAt(i); - String name = - DigestAlgorithm.fromOID(dai.getOID()).toString(); - MessageDigest md = - MessageDigest.getInstance(name); + AlgorithmIdentifier dai = (AlgorithmIdentifier) dias.elementAt(i); + String name = DigestAlgorithm.fromOID(dai.getOID()).toString(); + MessageDigest md = MessageDigest.getInstance(name); byte[] digest = md.digest(content.toByteArray()); digs.put(name, digest); } @@ -1230,8 +1380,7 @@ private boolean verifyRevRequestSignature(SignedData msgData) { SET sis = msgData.getSignerInfos(); int numSis = sis.size(); for (int i = 0; i < numSis; i++) { - org.mozilla.jss.pkix.cms.SignerInfo si = - (org.mozilla.jss.pkix.cms.SignerInfo) sis.elementAt(i); + org.mozilla.jss.pkix.cms.SignerInfo si = (org.mozilla.jss.pkix.cms.SignerInfo) sis.elementAt(i); String name = si.getDigestAlgorithm().toString(); byte[] digest = digs.get(name); if (digest == null) { @@ -1242,17 +1391,15 @@ private boolean verifyRevRequestSignature(SignedData msgData) { } SignerIdentifier sid = si.getSignerIdentifier(); if (sid.getType().equals(SignerIdentifier.ISSUER_AND_SERIALNUMBER)) { - org.mozilla.jss.pkix.cms.IssuerAndSerialNumber issuerAndSerialNumber = - sid.getIssuerAndSerialNumber(); + org.mozilla.jss.pkix.cms.IssuerAndSerialNumber issuerAndSerialNumber = sid + .getIssuerAndSerialNumber(); java.security.cert.X509Certificate cert = null; if (msgData.hasCertificates()) { SET certs = msgData.getCertificates(); int numCerts = certs.size(); for (int j = 0; j < numCerts; j++) { - org.mozilla.jss.pkix.cert.Certificate certJss = - (Certificate) certs.elementAt(j); - org.mozilla.jss.pkix.cert.CertificateInfo certI = - certJss.getInfo(); + org.mozilla.jss.pkix.cert.Certificate certJss = (Certificate) certs.elementAt(j); + org.mozilla.jss.pkix.cert.CertificateInfo certI = certJss.getInfo(); Name issuer = certI.getIssuer(); byte[] issuerB = ASN1Util.encode(issuer); INTEGER sn = certI.getSerialNumber(); @@ -1268,11 +1415,33 @@ private boolean verifyRevRequestSignature(SignedData msgData) { } if (cert != null) { + CMS.debug(method + "found cert"); PublicKey pbKey = cert.getPublicKey(); PK11PubKey pubK = PK11PubKey.fromSPKI(((X509Key) pbKey).getKey()); si.verify(digest, ci.getContentType(), pubK); + + // now check validity of the cert + java.security.cert.X509Certificate[] x509Certs = new java.security.cert.X509Certificate[1]; + x509Certs[0] = cert; + if (CMS.isRevoked(x509Certs)) { + CMS.debug(method + "CMC signing cert is a revoked certificate"); + return false; + } + try { + cert.checkValidity(); + } catch (CertificateExpiredException e) { + CMS.debug(method + "CMC signing cert is an expired certificate"); + return false; + } catch (Exception e) { + return false; + } + return true; + } else { + CMS.debug(method + "cert not found"); } + } else { + CMS.debug(method + "unsupported SignerIdentifier for CMC revocation"); } } diff --git a/base/server/cms/src/com/netscape/cms/servlet/common/GenPendingTemplateFiller.java b/base/server/cms/src/com/netscape/cms/servlet/common/GenPendingTemplateFiller.java index 83a2d8cf03e..4578a988abc 100644 --- a/base/server/cms/src/com/netscape/cms/servlet/common/GenPendingTemplateFiller.java +++ b/base/server/cms/src/com/netscape/cms/servlet/common/GenPendingTemplateFiller.java @@ -158,9 +158,9 @@ public CMSTemplateParams getTemplateParams( byte[] dig; try { - MessageDigest SHA1Digest = MessageDigest.getInstance("SHA1"); + MessageDigest SHA2Digest = MessageDigest.getInstance("SHA256"); - dig = SHA1Digest.digest(salt.getBytes()); + dig = SHA2Digest.digest(salt.getBytes()); } catch (NoSuchAlgorithmException ex) { dig = salt.getBytes(); } @@ -199,16 +199,15 @@ public CMSTemplateParams getTemplateParams( SignerIdentifier si = new SignerIdentifier(SignerIdentifier.ISSUER_AND_SERIALNUMBER, ias, null); - // SHA1 is the default digest Alg for now. DigestAlgorithm digestAlg = null; SignatureAlgorithm signAlg = null; org.mozilla.jss.crypto.PrivateKey privKey = CryptoManager.getInstance().findPrivKeyByCert(x509cert); org.mozilla.jss.crypto.PrivateKey.Type keyType = privKey.getType(); if (keyType.equals(org.mozilla.jss.crypto.PrivateKey.RSA)) { - signAlg = SignatureAlgorithm.RSASignatureWithSHA1Digest; - } else if (keyType.equals(org.mozilla.jss.crypto.PrivateKey.DSA)) { - signAlg = SignatureAlgorithm.DSASignatureWithSHA1Digest; + signAlg = SignatureAlgorithm.RSASignatureWithSHA256Digest; + } else if (keyType.equals(org.mozilla.jss.crypto.PrivateKey.EC)) { + signAlg = SignatureAlgorithm.ECSignatureWithSHA256Digest; } else { CMS.debug("GenPendingTemplateFiller::getTemplateParams() - " + "keyType " + keyType.toString() @@ -220,8 +219,8 @@ public CMSTemplateParams getTemplateParams( byte[] digest = null; try { - SHADigest = MessageDigest.getInstance("SHA1"); - digestAlg = DigestAlgorithm.SHA1; + SHADigest = MessageDigest.getInstance("SHA256"); + digestAlg = DigestAlgorithm.SHA256; ByteArrayOutputStream ostream = new ByteArrayOutputStream(); diff --git a/base/server/cms/src/com/netscape/cms/servlet/profile/ProfileSubmitCMCServlet.java b/base/server/cms/src/com/netscape/cms/servlet/profile/ProfileSubmitCMCServlet.java index 93039a4863d..330b5ff6601 100644 --- a/base/server/cms/src/com/netscape/cms/servlet/profile/ProfileSubmitCMCServlet.java +++ b/base/server/cms/src/com/netscape/cms/servlet/profile/ProfileSubmitCMCServlet.java @@ -413,7 +413,7 @@ public void process(CMSRequest cmsReq) throws EBaseException { } setInputsIntoContext(request, profile, ctx); - CMS.debug("ProfileSubmistServlet: set Inputs into Context"); + CMS.debug("ProfileSubmitCMCServlet: set Inputs into Context"); // before creating the request, authenticate the request @@ -560,9 +560,14 @@ public void process(CMSRequest cmsReq) throws EBaseException { // In case of decryptedPOP, request already exists, find it and // put in provedReq. IRequest provedReq = null; + boolean isRevoke = false; if (reqs == null) { // handling DecryptedPOP request here Integer reqID = (Integer) context.get("cmcDecryptedPopReqId"); + if (reqID == null) { + CMS.debug("ProfileSubmitCMCServlet: revocation request"); + isRevoke = true; + } else { provedReq = profile.getRequestQueue().findRequest(new RequestId(reqID.toString())); if (provedReq == null) { @@ -584,6 +589,7 @@ public void process(CMSRequest cmsReq) throws EBaseException { } else { CMS.debug("ProfileSubmitCMCServlet: provedReq not null"); } + } } String errorCode = null; @@ -592,7 +598,7 @@ public void process(CMSRequest cmsReq) throws EBaseException { /////////////////////////////////////////////// // populate request /////////////////////////////////////////////// - for (int k = 0; (provedReq == null) &&(k < reqs.length); k++) { + for (int k = 0; (!isRevoke) && (provedReq == null) &&(k < reqs.length); k++) { // adding parameters to request setInputsIntoRequest(request, profile, reqs[k]); @@ -712,7 +718,7 @@ public void process(CMSRequest cmsReq) throws EBaseException { if (reqs != null && reqs.length > 0) error_codes = new int[reqs.length]; - for (int k = 0; (provedReq == null) && (k < reqs.length); k++) { + for (int k = 0; (!isRevoke) && (provedReq == null) && (k < reqs.length); k++) { try { // reset the "auditRequesterID" auditRequesterID = auditRequesterID(reqs[k]); diff --git a/base/server/cmscore/src/com/netscape/cmscore/apps/CMSEngine.java b/base/server/cmscore/src/com/netscape/cmscore/apps/CMSEngine.java index 94a0783ab7c..b111f71d336 100644 --- a/base/server/cmscore/src/com/netscape/cmscore/apps/CMSEngine.java +++ b/base/server/cmscore/src/com/netscape/cmscore/apps/CMSEngine.java @@ -62,6 +62,7 @@ import org.w3c.dom.Element; import org.w3c.dom.NodeList; +import com.netscape.certsrv.authentication.ISharedToken; import com.netscape.certsrv.acls.ACL; import com.netscape.certsrv.acls.ACLEntry; import com.netscape.certsrv.acls.EACLsException; @@ -1912,6 +1913,38 @@ public IPasswordCheck getPasswordChecker() { } } + public ISharedToken getSharedTokenClass(String configName) { + String method = "CMSEngine: 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; + } + public ILogger getLogger() { return Logger.getLogger(); } diff --git a/base/server/test/com/netscape/cmscore/app/CMSEngineDefaultStub.java b/base/server/test/com/netscape/cmscore/app/CMSEngineDefaultStub.java index dd28adb5689..b314dacae32 100644 --- a/base/server/test/com/netscape/cmscore/app/CMSEngineDefaultStub.java +++ b/base/server/test/com/netscape/cmscore/app/CMSEngineDefaultStub.java @@ -23,6 +23,7 @@ import com.netscape.certsrv.acls.IACL; import com.netscape.certsrv.apps.ICMSEngine; import com.netscape.certsrv.apps.ICommandQueue; +import com.netscape.certsrv.authentication.ISharedToken; import com.netscape.certsrv.authority.IAuthority; import com.netscape.certsrv.base.EBaseException; import com.netscape.certsrv.base.IArgBlock; @@ -370,6 +371,10 @@ public IPasswordCheck getPasswordChecker() { return null; } + public ISharedToken getSharedTokenClass(String configName) { + return null; + } + public void putPasswordCache(String tag, String pw) { } diff --git a/base/util/src/com/netscape/cmsutil/util/Utils.java b/base/util/src/com/netscape/cmsutil/util/Utils.java index 98becdc4c52..933432d8d57 100644 --- a/base/util/src/com/netscape/cmsutil/util/Utils.java +++ b/base/util/src/com/netscape/cmsutil/util/Utils.java @@ -285,6 +285,11 @@ public static String base64encode(byte[] bytes) { return string; } + public static String base64encodeSingleLine(byte[] bytes) { + String string = new Base64().encodeToString(bytes); + return string; + } + public static byte[] base64decode(String string) { byte[] bytes = Base64.decodeBase64(string); return bytes;