From cc50605b73b822bc9d47799122473d2d58e61b9d Mon Sep 17 00:00:00 2001
From: Christina Fu <cfu@redhat.com>
Date: Mon, 15 May 2017 18:15:36 -0700
Subject: [PATCH] Bug 1447080 - CC: 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.

---
 base/ca/shared/conf/CS.cfg                         |   8 +-
 .../shared/profiles/ca/caFullCMCSelfSignedCert.cfg |  85 ++++
 base/ca/shared/webapps/ca/WEB-INF/web.xml          |  28 ++
 .../certsrv/authentication/IAuthManager.java       |   1 +
 .../certsrv/authentication/IAuthSubsystem.java     |   5 +
 .../com/netscape/certsrv/logging/AuditEvent.java   |  16 +-
 .../src/com/netscape/cmstools/CMCRequest.java      | 166 ++++++-
 .../src/com/netscape/cmstools/CRMFPopClient.java   |  32 ++
 .../src/com/netscape/cmstools/PKCS10Client.java    |  87 ++--
 .../cms/authentication/CMCUserSignedAuth.java      | 543 +++++++++++++--------
 .../netscape/cms/profile/common/EnrollProfile.java | 163 ++++++-
 .../netscape/cms/profile/def/CAEnrollDefault.java  |  37 +-
 .../def/SubjectKeyIdentifierExtDefault.java        |  21 +-
 .../netscape/cms/profile/input/EnrollInput.java    |   8 +-
 .../cms/servlet/processors/CRMFProcessor.java      |  18 +-
 .../servlet/profile/ProfileSubmitCMCServlet.java   |  49 +-
 base/server/cmsbundle/src/LogMessages.properties   |  32 +-
 .../com/netscape/cmscore/security/KeyCertUtil.java |  12 +-
 .../com/netscape/cmsutil/crypto/CryptoUtil.java    | 181 ++++++-
 base/util/src/netscape/security/pkcs/PKCS10.java   |  31 +-
 .../netscape/security/pkcs/PKCS10Attributes.java   |   2 +
 21 files changed, 1145 insertions(+), 380 deletions(-)
 create mode 100644 base/ca/shared/profiles/ca/caFullCMCSelfSignedCert.cfg

diff --git a/base/ca/shared/conf/CS.cfg b/base/ca/shared/conf/CS.cfg
index 3eb5b1b..9331c25 100644
--- a/base/ca/shared/conf/CS.cfg
+++ b/base/ca/shared/conf/CS.cfg
@@ -908,11 +908,11 @@ log.instance.SignedAudit._001=## Signed Audit Logging
 log.instance.SignedAudit._002=##
 log.instance.SignedAudit._003=##
 log.instance.SignedAudit._004=## Available Audit events:
-log.instance.SignedAudit._005=## AUDIT_LOG_STARTUP,AUDIT_LOG_SHUTDOWN,ROLE_ASSUME,CONFIG_CERT_POLICY,CONFIG_CERT_PROFILE,CONFIG_CRL_PROFILE,CONFIG_OCSP_PROFILE,CONFIG_AUTH,CONFIG_ROLE,CONFIG_ACL,CONFIG_SIGNED_AUDIT,CONFIG_ENCRYPTION,CONFIG_TRUSTED_PUBLIC_KEY,CONFIG_DRM,SELFTESTS_EXECUTION,AUDIT_LOG_DELETE,LOG_PATH_CHANGE,LOG_EXPIRATION_CHANGE,PRIVATE_KEY_ARCHIVE_REQUEST,PRIVATE_KEY_ARCHIVE_REQUEST_PROCESSED,PRIVATE_KEY_EXPORT_REQUEST_PROCESSED_SUCCESS,PRIVATE_KEY_EXPORT_REQUEST_PROCESSED_FAILURE,KEY_RECOVERY_REQUEST,KEY_RECOVERY_REQUEST_ASYNC,KEY_RECOVERY_AGENT_LOGIN,KEY_RECOVERY_REQUEST_PROCESSED,KEY_RECOVERY_REQUEST_PROCESSED_ASYNC,KEY_GEN_ASYMMETRIC,NON_PROFILE_CERT_REQUEST,PROFILE_CERT_REQUEST,CERT_REQUEST_PROCESSED,CERT_STATUS_CHANGE_REQUEST,CERT_STATUS_CHANGE_REQUEST_PROCESSED,AUTHZ_SUCCESS,AUTHZ_FAIL,INTER_BOUNDARY,AUTH_FAIL,AUTH_SUCCESS,CERT_PROFILE_APPROVAL,PROOF_OF_POSSESSION,CRL_RETRIEVAL,CRL_VALIDATION,CMC_SIGNED_REQUEST_SIG_VERIFY,CMC_USER_SIGNED_REQUEST_SIG_VERIFY,SERVER_SIDE_KEYGEN_REQUEST_PROCESSED_FAILURE,SERVER_SIDE_KEYGEN_REQUEST_PROCESSED_SUCCESS,SERVER_SIDE_KEYGEN_REQUEST,COMPUTE_SESSION_KEY_REQUEST,COMPUTE_SESSION_KEY_REQUEST_PROCESSED_SUCCESS, COMPUTE_SESSION_KEY_REQUEST_PROCESSED_FAILURE,DIVERSIFY_KEY_REQUEST,DIVERSIFY_KEY_REQUEST_PROCESSED_SUCCESS, DIVERSIFY_KEY_REQUEST_PROCESSED_FAILURE,ENCRYPT_DATA_REQUEST,ENCRYPT_DATA_REQUEST_PROCESSED_SUCCESS,ENCRYPT_DATA_REQUEST_PROCESSED_FAILURE,OCSP_ADD_CA_REQUEST,OCSP_ADD_CA_REQUEST_PROCESSED,OCSP_REMOVE_CA_REQUEST,OCSP_REMOVE_CA_REQUEST_PROCESSED_SUCCESS,OCSP_REMOVE_CA_REQUEST_PROCESSED_FAILURE,COMPUTE_RANDOM_DATA_REQUEST,COMPUTE_RANDOM_DATA_REQUEST_PROCESSED_SUCCESS,COMPUTE_RANDOM_DATA_REQUEST_PROCESSED_FAILURE,CIMC_CERT_VERIFICATION,SECURITY_DOMAIN_UPDATE,CONFIG_SERIAL_NUMBER,AUTHORITY_CONFIG,ACCESS_SESSION_ESTABLISH_FAILURE,ACCESS_SESSION_ESTABLISH_SUCCESS,ACCESS_SESSION_TERMINATED
+log.instance.SignedAudit._005=## AUDIT_LOG_STARTUP,AUDIT_LOG_SHUTDOWN,ROLE_ASSUME,CONFIG_CERT_POLICY,CONFIG_CERT_PROFILE,CONFIG_CRL_PROFILE,CONFIG_OCSP_PROFILE,CONFIG_AUTH,CONFIG_ROLE,CONFIG_ACL,CONFIG_SIGNED_AUDIT,CONFIG_ENCRYPTION,CONFIG_TRUSTED_PUBLIC_KEY,CONFIG_DRM,SELFTESTS_EXECUTION,AUDIT_LOG_DELETE,LOG_PATH_CHANGE,LOG_EXPIRATION_CHANGE,PRIVATE_KEY_ARCHIVE_REQUEST,PRIVATE_KEY_ARCHIVE_REQUEST_PROCESSED,PRIVATE_KEY_EXPORT_REQUEST_PROCESSED_SUCCESS,PRIVATE_KEY_EXPORT_REQUEST_PROCESSED_FAILURE,KEY_RECOVERY_REQUEST,KEY_RECOVERY_REQUEST_ASYNC,KEY_RECOVERY_AGENT_LOGIN,KEY_RECOVERY_REQUEST_PROCESSED,KEY_RECOVERY_REQUEST_PROCESSED_ASYNC,KEY_GEN_ASYMMETRIC,NON_PROFILE_CERT_REQUEST,PROFILE_CERT_REQUEST,CERT_REQUEST_PROCESSED,CERT_STATUS_CHANGE_REQUEST,CERT_STATUS_CHANGE_REQUEST_PROCESSED,AUTHZ_SUCCESS,AUTHZ_FAIL,INTER_BOUNDARY,AUTH_FAIL,AUTH_SUCCESS,CERT_PROFILE_APPROVAL,PROOF_OF_POSSESSION_SUCCESS,PROOF_OF_POSSESSION_FAILURE,CMC_PROOF_OF_IDENTIFICATION_SUCCESS,CMC_PROOF_OF_IDENTIFICATION_FAILURE,CRL_RETRIEVAL,CRL_VALIDATION,CMC_SIGNED_REQUEST_SIG_VERIFY,CMC_USER_SIGNED_REQUEST_SIG_VERIFY_SUCCESS,CMC_USER_SIGNED_REQUEST_SIG_VERIFY_FAILURE,SERVER_SIDE_KEYGEN_REQUEST_PROCESSED_FAILURE,SERVER_SIDE_KEYGEN_REQUEST_PROCESSED_SUCCESS,SERVER_SIDE_KEYGEN_REQUEST,COMPUTE_SESSION_KEY_REQUEST,COMPUTE_SESSION_KEY_REQUEST_PROCESSED_SUCCESS, COMPUTE_SESSION_KEY_REQUEST_PROCESSED_FAILURE,DIVERSIFY_KEY_REQUEST,DIVERSIFY_KEY_REQUEST_PROCESSED_SUCCESS, DIVERSIFY_KEY_REQUEST_PROCESSED_FAILURE,ENCRYPT_DATA_REQUEST,ENCRYPT_DATA_REQUEST_PROCESSED_SUCCESS,ENCRYPT_DATA_REQUEST_PROCESSED_FAILURE,OCSP_ADD_CA_REQUEST,OCSP_ADD_CA_REQUEST_PROCESSED,OCSP_REMOVE_CA_REQUEST,OCSP_REMOVE_CA_REQUEST_PROCESSED_SUCCESS,OCSP_REMOVE_CA_REQUEST_PROCESSED_FAILURE,COMPUTE_RANDOM_DATA_REQUEST,COMPUTE_RANDOM_DATA_REQUEST_PROCESSED_SUCCESS,COMPUTE_RANDOM_DATA_REQUEST_PROCESSED_FAILURE,CIMC_CERT_VERIFICATION,SECURITY_DOMAIN_UPDATE,CONFIG_SERIAL_NUMBER,AUTHORITY_CONFIG,ACCESS_SESSION_ESTABLISH_FAILURE,ACCESS_SESSION_ESTABLISH_SUCCESS,ACCESS_SESSION_TERMINATED
 log.instance.SignedAudit._006=##
 log.instance.SignedAudit.bufferSize=512
 log.instance.SignedAudit.enable=true
-log.instance.SignedAudit.events=AUDIT_LOG_STARTUP,AUDIT_LOG_SHUTDOWN,ROLE_ASSUME,CONFIG_CERT_POLICY,CONFIG_CERT_PROFILE,CONFIG_CRL_PROFILE,CONFIG_OCSP_PROFILE,CONFIG_AUTH,CONFIG_ROLE,CONFIG_ACL,CONFIG_SIGNED_AUDIT,CONFIG_ENCRYPTION,CONFIG_TRUSTED_PUBLIC_KEY,CONFIG_DRM,SELFTESTS_EXECUTION,AUDIT_LOG_DELETE,LOG_PATH_CHANGE,PRIVATE_KEY_ARCHIVE_REQUEST,PRIVATE_KEY_ARCHIVE_REQUEST_PROCESSED,PRIVATE_KEY_EXPORT_REQUEST_PROCESSED_SUCCESS,PRIVATE_KEY_EXPORT_REQUEST_PROCESSED_FAILURE,KEY_RECOVERY_REQUEST,KEY_RECOVERY_REQUEST_ASYNC,KEY_RECOVERY_AGENT_LOGIN,KEY_RECOVERY_REQUEST_PROCESSED,KEY_RECOVERY_REQUEST_PROCESSED_ASYNC,KEY_GEN_ASYMMETRIC,NON_PROFILE_CERT_REQUEST,PROFILE_CERT_REQUEST,CERT_REQUEST_PROCESSED,CERT_STATUS_CHANGE_REQUEST,CERT_STATUS_CHANGE_REQUEST_PROCESSED,AUTHZ_SUCCESS,AUTHZ_FAIL,INTER_BOUNDARY,AUTH_FAIL,AUTH_SUCCESS,CERT_PROFILE_APPROVAL,PROOF_OF_POSSESSION,CRL_RETRIEVAL,CRL_VALIDATION,CMC_SIGNED_REQUEST_SIG_VERIFY,CMC_USER_SIGNED_REQUEST_SIG_VERIFY,SERVER_SIDE_KEYGEN_REQUEST_PROCESSED_FAILURE,SERVER_SIDE_KEYGEN_REQUEST_PROCESSED_SUCCESS,SERVER_SIDE_KEYGEN_REQUEST,COMPUTE_SESSION_KEY_REQUEST,COMPUTE_SESSION_KEY_REQUEST_PROCESSED_SUCCESS, COMPUTE_SESSION_KEY_REQUEST_PROCESSED_FAILURE,DIVERSIFY_KEY_REQUEST,DIVERSIFY_KEY_REQUEST_PROCESSED_SUCCESS, DIVERSIFY_KEY_REQUEST_PROCESSED_FAILURE,ENCRYPT_DATA_REQUEST,ENCRYPT_DATA_REQUEST_PROCESSED_SUCCESS,ENCRYPT_DATA_REQUEST_PROCESSED_FAILURE,OCSP_ADD_CA_REQUEST,OCSP_ADD_CA_REQUEST_PROCESSED,OCSP_REMOVE_CA_REQUEST,OCSP_REMOVE_CA_REQUEST_PROCESSED_SUCCESS,OCSP_REMOVE_CA_REQUEST_PROCESSED_FAILURE,COMPUTE_RANDOM_DATA_REQUEST,COMPUTE_RANDOM_DATA_REQUEST_PROCESSED_SUCCESS,COMPUTE_RANDOM_DATA_REQUEST_PROCESSED_FAILURE,CIMC_CERT_VERIFICATION,SECURITY_DOMAIN_UPDATE,CONFIG_SERIAL_NUMBER,AUTHORITY_CONFIG,ACCESS_SESSION_ESTABLISH_FAILURE,ACCESS_SESSION_ESTABLISH_SUCCESS,ACCESS_SESSION_TERMINATED
+log.instance.SignedAudit.events=AUDIT_LOG_STARTUP,AUDIT_LOG_SHUTDOWN,ROLE_ASSUME,CONFIG_CERT_POLICY,CONFIG_CERT_PROFILE,CONFIG_CRL_PROFILE,CONFIG_OCSP_PROFILE,CONFIG_AUTH,CONFIG_ROLE,CONFIG_ACL,CONFIG_SIGNED_AUDIT,CONFIG_ENCRYPTION,CONFIG_TRUSTED_PUBLIC_KEY,CONFIG_DRM,SELFTESTS_EXECUTION,AUDIT_LOG_DELETE,LOG_PATH_CHANGE,PRIVATE_KEY_ARCHIVE_REQUEST,PRIVATE_KEY_ARCHIVE_REQUEST_PROCESSED,PRIVATE_KEY_EXPORT_REQUEST_PROCESSED_SUCCESS,PRIVATE_KEY_EXPORT_REQUEST_PROCESSED_FAILURE,KEY_RECOVERY_REQUEST,KEY_RECOVERY_REQUEST_ASYNC,KEY_RECOVERY_AGENT_LOGIN,KEY_RECOVERY_REQUEST_PROCESSED,KEY_RECOVERY_REQUEST_PROCESSED_ASYNC,KEY_GEN_ASYMMETRIC,NON_PROFILE_CERT_REQUEST,PROFILE_CERT_REQUEST,CERT_REQUEST_PROCESSED,CERT_STATUS_CHANGE_REQUEST,CERT_STATUS_CHANGE_REQUEST_PROCESSED,AUTHZ_SUCCESS,AUTHZ_FAIL,INTER_BOUNDARY,AUTH_FAIL,AUTH_SUCCESS,CERT_PROFILE_APPROVAL,PROOF_OF_POSSESSION_SUCCESS,PROOF_OF_POSSESSION_FAILURE,CMC_PROOF_OF_IDENTIFICATION_SUCCESS,CMC_PROOF_OF_IDENTIFICATION_FAILURE,CRL_RETRIEVAL,CRL_VALIDATION,CMC_SIGNED_REQUEST_SIG_VERIFY,CMC_USER_SIGNED_REQUEST_SIG_VERIFY_SUCCESS,CMC_USER_SIGNED_REQUEST_SIG_VERIFY_FAILURE,SERVER_SIDE_KEYGEN_REQUEST_PROCESSED_FAILURE,SERVER_SIDE_KEYGEN_REQUEST_PROCESSED_SUCCESS,SERVER_SIDE_KEYGEN_REQUEST,COMPUTE_SESSION_KEY_REQUEST,COMPUTE_SESSION_KEY_REQUEST_PROCESSED_SUCCESS, COMPUTE_SESSION_KEY_REQUEST_PROCESSED_FAILURE,DIVERSIFY_KEY_REQUEST,DIVERSIFY_KEY_REQUEST_PROCESSED_SUCCESS, DIVERSIFY_KEY_REQUEST_PROCESSED_FAILURE,ENCRYPT_DATA_REQUEST,ENCRYPT_DATA_REQUEST_PROCESSED_SUCCESS,ENCRYPT_DATA_REQUEST_PROCESSED_FAILURE,OCSP_ADD_CA_REQUEST,OCSP_ADD_CA_REQUEST_PROCESSED,OCSP_REMOVE_CA_REQUEST,OCSP_REMOVE_CA_REQUEST_PROCESSED_SUCCESS,OCSP_REMOVE_CA_REQUEST_PROCESSED_FAILURE,COMPUTE_RANDOM_DATA_REQUEST,COMPUTE_RANDOM_DATA_REQUEST_PROCESSED_SUCCESS,COMPUTE_RANDOM_DATA_REQUEST_PROCESSED_FAILURE,CIMC_CERT_VERIFICATION,SECURITY_DOMAIN_UPDATE,CONFIG_SERIAL_NUMBER,AUTHORITY_CONFIG,ACCESS_SESSION_ESTABLISH_FAILURE,ACCESS_SESSION_ESTABLISH_SUCCESS,ACCESS_SESSION_TERMINATED
 log.instance.SignedAudit.expirationTime=0
 log.instance.SignedAudit.fileName=[PKI_INSTANCE_PATH]/logs/[PKI_SUBSYSTEM_TYPE]/signedAudit/ca_audit
 log.instance.SignedAudit.flushInterval=5
@@ -971,7 +971,7 @@ oidmap.pse.oid=2.16.840.1.113730.1.18
 oidmap.subject_info_access.class=netscape.security.extensions.SubjectInfoAccessExtension
 oidmap.subject_info_access.oid=1.3.6.1.5.5.7.1.11
 os.userid=nobody
-profile.list=caUserCert,caECUserCert,caUserSMIMEcapCert,caDualCert,caDirBasedDualCert,caECDualCert,AdminCert,caSignedLogCert,caTPSCert,caRARouterCert,caRouterCert,caServerCert,caSubsystemCert,caOtherCert,caCACert,caCrossSignedCACert,caInstallCACert,caRACert,caOCSPCert,caStorageCert,caTransportCert,caDirPinUserCert,caDirUserCert,caECDirUserCert,caAgentServerCert,caAgentFileSigning,caCMCUserCert,caFullCMCUserCert,caFullCMCUserSignedCert,caSimpleCMCUserCert,caTokenDeviceKeyEnrollment,caTokenUserEncryptionKeyEnrollment,caTokenUserSigningKeyEnrollment,caTempTokenDeviceKeyEnrollment,caTempTokenUserEncryptionKeyEnrollment,caTempTokenUserSigningKeyEnrollment,caAdminCert,caInternalAuthServerCert,caInternalAuthTransportCert,caInternalAuthDRMstorageCert,caInternalAuthSubsystemCert,caInternalAuthOCSPCert,caInternalAuthAuditSigningCert,DomainController,caDualRAuserCert,caRAagentCert,caRAserverCert,caUUIDdeviceCert,caSSLClientSelfRenewal,caDirUserRenewal,caManualRenewal,caTokenMSLoginEnrollment,caTokenUserSigningKeyRenewal,caTokenUserEncryptionKeyRenewal,caTokenUserAuthKeyRenewal,caJarSigningCert,caIPAserviceCert,caEncUserCert,caSigningUserCert,caSigningECUserCert,caEncECUserCert,caTokenUserDelegateAuthKeyEnrollment,caTokenUserDelegateSigningKeyEnrollment
+profile.list=caUserCert,caECUserCert,caUserSMIMEcapCert,caDualCert,caDirBasedDualCert,caECDualCert,AdminCert,caSignedLogCert,caTPSCert,caRARouterCert,caRouterCert,caServerCert,caSubsystemCert,caOtherCert,caCACert,caCrossSignedCACert,caInstallCACert,caRACert,caOCSPCert,caStorageCert,caTransportCert,caDirPinUserCert,caDirUserCert,caECDirUserCert,caAgentServerCert,caAgentFileSigning,caCMCUserCert,caFullCMCUserCert,caFullCMCUserSignedCert,caFullCMCSelfSignedCert,caSimpleCMCUserCert,caTokenDeviceKeyEnrollment,caTokenUserEncryptionKeyEnrollment,caTokenUserSigningKeyEnrollment,caTempTokenDeviceKeyEnrollment,caTempTokenUserEncryptionKeyEnrollment,caTempTokenUserSigningKeyEnrollment,caAdminCert,caInternalAuthServerCert,caInternalAuthTransportCert,caInternalAuthDRMstorageCert,caInternalAuthSubsystemCert,caInternalAuthOCSPCert,caInternalAuthAuditSigningCert,DomainController,caDualRAuserCert,caRAagentCert,caRAserverCert,caUUIDdeviceCert,caSSLClientSelfRenewal,caDirUserRenewal,caManualRenewal,caTokenMSLoginEnrollment,caTokenUserSigningKeyRenewal,caTokenUserEncryptionKeyRenewal,caTokenUserAuthKeyRenewal,caJarSigningCert,caIPAserviceCert,caEncUserCert,caSigningUserCert,caSigningECUserCert,caEncECUserCert,caTokenUserDelegateAuthKeyEnrollment,caTokenUserDelegateSigningKeyEnrollment
 profile.caUUIDdeviceCert.class_id=caEnrollImpl
 profile.caUUIDdeviceCert.config=[PKI_INSTANCE_PATH]/[PKI_SUBSYSTEM_TYPE]/profiles/ca/caUUIDdeviceCert.cfg
 profile.caManualRenewal.class_id=caEnrollImpl
@@ -1018,6 +1018,8 @@ profile.caFullCMCUserCert.class_id=caEnrollImpl
 profile.caFullCMCUserCert.config=[PKI_INSTANCE_PATH]/[PKI_SUBSYSTEM_TYPE]/profiles/ca/caFullCMCUserCert.cfg
 profile.caFullCMCUserSignedCert.class_id=caEnrollImpl
 profile.caFullCMCUserSignedCert.config=[PKI_INSTANCE_PATH]/[PKI_SUBSYSTEM_TYPE]/profiles/ca/caFullCMCUserSignedCert.cfg
+profile.caFullCMCSelfSignedCert.class_id=caEnrollImpl
+profile.caFullCMCSelfSignedCert.config=[PKI_INSTANCE_PATH]/[PKI_SUBSYSTEM_TYPE]/profiles/ca/caFullCMCSelfSignedCert.cfg
 profile.caInternalAuthOCSPCert.class_id=caEnrollImpl
 profile.caInternalAuthOCSPCert.config=[PKI_INSTANCE_PATH]/[PKI_SUBSYSTEM_TYPE]/profiles/ca/caInternalAuthOCSPCert.cfg
 profile.caInternalAuthAuditSigningCert.class_id=caEnrollImpl
diff --git a/base/ca/shared/profiles/ca/caFullCMCSelfSignedCert.cfg b/base/ca/shared/profiles/ca/caFullCMCSelfSignedCert.cfg
new file mode 100644
index 0000000..db3fbd6
--- /dev/null
+++ b/base/ca/shared/profiles/ca/caFullCMCSelfSignedCert.cfg
@@ -0,0 +1,85 @@
+desc=This certificate profile is for enrolling user certificates by using the self-signed CMC certificate request
+enable=true
+enableBy=admin
+name=Self-Signed CMC User Certificate Enrollment
+visible=false
+auth.instance_id=CMCUserSignedAuth
+input.list=i1,i2
+input.i1.class_id=cmcCertReqInputImpl
+input.i2.class_id=submitterInfoInputImpl
+output.list=o1
+output.o1.class_id=certOutputImpl
+policyset.list=cmcUserCertSet
+policyset.cmcUserCertSet.list=1,2,3,4,5,6,7,8
+policyset.cmcUserCertSet.1.constraint.class_id=subjectNameConstraintImpl
+policyset.cmcUserCertSet.1.constraint.name=Subject Name Constraint
+policyset.cmcUserCertSet.1.constraint.params.accept=true
+policyset.cmcUserCertSet.1.constraint.params.pattern=.*
+policyset.cmcUserCertSet.1.default.class_id=userSubjectNameDefaultImpl
+policyset.cmcUserCertSet.1.default.name=Subject Name Default
+policyset.cmcUserCertSet.1.default.params.name=
+policyset.cmcUserCertSet.2.constraint.class_id=validityConstraintImpl
+policyset.cmcUserCertSet.2.constraint.name=Validity Constraint
+policyset.cmcUserCertSet.2.constraint.params.notAfterCheck=false
+policyset.cmcUserCertSet.2.constraint.params.notBeforeCheck=false
+policyset.cmcUserCertSet.2.constraint.params.range=365
+policyset.cmcUserCertSet.2.default.class_id=validityDefaultImpl
+policyset.cmcUserCertSet.2.default.name=Validity Default
+policyset.cmcUserCertSet.2.default.params.range=180
+policyset.cmcUserCertSet.2.default.params.startTime=0
+policyset.cmcUserCertSet.3.constraint.class_id=keyConstraintImpl
+policyset.cmcUserCertSet.3.constraint.name=Key Constraint
+policyset.cmcUserCertSet.3.constraint.params.keyParameters=1024,2048,3072,4096,nistp256,nistp521
+policyset.cmcUserCertSet.3.constraint.params.keyType=-
+policyset.cmcUserCertSet.3.default.class_id=userKeyDefaultImpl
+policyset.cmcUserCertSet.3.default.name=Key Default
+policyset.cmcUserCertSet.4.constraint.class_id=noConstraintImpl
+policyset.cmcUserCertSet.4.constraint.name=No Constraint
+policyset.cmcUserCertSet.4.default.class_id=authorityKeyIdentifierExtDefaultImpl
+policyset.cmcUserCertSet.4.default.name=Authority Key Identifier Default
+policyset.cmcUserCertSet.5.constraint.class_id=noConstraintImpl
+policyset.cmcUserCertSet.5.constraint.name=No Constraint
+policyset.cmcUserCertSet.5.default.class_id=authInfoAccessExtDefaultImpl
+policyset.cmcUserCertSet.5.default.name=AIA Extension Default
+policyset.cmcUserCertSet.5.default.params.authInfoAccessADEnable_0=true
+policyset.cmcUserCertSet.5.default.params.authInfoAccessADLocationType_0=URIName
+policyset.cmcUserCertSet.5.default.params.authInfoAccessADLocation_0=
+policyset.cmcUserCertSet.5.default.params.authInfoAccessADMethod_0=1.3.6.1.5.5.7.48.1
+policyset.cmcUserCertSet.5.default.params.authInfoAccessCritical=false
+policyset.cmcUserCertSet.5.default.params.authInfoAccessNumADs=1
+policyset.cmcUserCertSet.6.constraint.class_id=keyUsageExtConstraintImpl
+policyset.cmcUserCertSet.6.constraint.name=Key Usage Extension Constraint
+policyset.cmcUserCertSet.6.constraint.params.keyUsageCritical=true
+policyset.cmcUserCertSet.6.constraint.params.keyUsageCrlSign=false
+policyset.cmcUserCertSet.6.constraint.params.keyUsageDataEncipherment=false
+policyset.cmcUserCertSet.6.constraint.params.keyUsageDecipherOnly=false
+policyset.cmcUserCertSet.6.constraint.params.keyUsageDigitalSignature=true
+policyset.cmcUserCertSet.6.constraint.params.keyUsageEncipherOnly=false
+policyset.cmcUserCertSet.6.constraint.params.keyUsageKeyAgreement=false
+policyset.cmcUserCertSet.6.constraint.params.keyUsageKeyCertSign=false
+policyset.cmcUserCertSet.6.constraint.params.keyUsageKeyEncipherment=true
+policyset.cmcUserCertSet.6.constraint.params.keyUsageNonRepudiation=true
+policyset.cmcUserCertSet.6.default.class_id=keyUsageExtDefaultImpl
+policyset.cmcUserCertSet.6.default.name=Key Usage Default
+policyset.cmcUserCertSet.6.default.params.keyUsageCritical=true
+policyset.cmcUserCertSet.6.default.params.keyUsageCrlSign=false
+policyset.cmcUserCertSet.6.default.params.keyUsageDataEncipherment=false
+policyset.cmcUserCertSet.6.default.params.keyUsageDecipherOnly=false
+policyset.cmcUserCertSet.6.default.params.keyUsageDigitalSignature=true
+policyset.cmcUserCertSet.6.default.params.keyUsageEncipherOnly=false
+policyset.cmcUserCertSet.6.default.params.keyUsageKeyAgreement=false
+policyset.cmcUserCertSet.6.default.params.keyUsageKeyCertSign=false
+policyset.cmcUserCertSet.6.default.params.keyUsageKeyEncipherment=true
+policyset.cmcUserCertSet.6.default.params.keyUsageNonRepudiation=true
+policyset.cmcUserCertSet.7.constraint.class_id=noConstraintImpl
+policyset.cmcUserCertSet.7.constraint.name=No Constraint
+policyset.cmcUserCertSet.7.default.class_id=extendedKeyUsageExtDefaultImpl
+policyset.cmcUserCertSet.7.default.name=Extended Key Usage Extension Default
+policyset.cmcUserCertSet.7.default.params.exKeyUsageCritical=false
+policyset.cmcUserCertSet.7.default.params.exKeyUsageOIDs=1.3.6.1.5.5.7.3.2,1.3.6.1.5.5.7.3.4
+policyset.cmcUserCertSet.8.constraint.class_id=signingAlgConstraintImpl
+policyset.cmcUserCertSet.8.constraint.name=No Constraint
+policyset.cmcUserCertSet.8.constraint.params.signingAlgsAllowed=SHA1withRSA,SHA256withRSA,SHA512withRSA,MD5withRSA,MD2withRSA,SHA1withDSA,SHA1withEC,SHA256withEC,SHA384withRSA,SHA384withEC,SHA512withEC
+policyset.cmcUserCertSet.8.default.class_id=signingAlgDefaultImpl
+policyset.cmcUserCertSet.8.default.name=Signing Alg
+policyset.cmcUserCertSet.8.default.params.signingAlg=-
diff --git a/base/ca/shared/webapps/ca/WEB-INF/web.xml b/base/ca/shared/webapps/ca/WEB-INF/web.xml
index dc61ab3..a550142 100644
--- a/base/ca/shared/webapps/ca/WEB-INF/web.xml
+++ b/base/ca/shared/webapps/ca/WEB-INF/web.xml
@@ -1576,6 +1576,29 @@
    </servlet>
 
    <servlet>
+      <servlet-name>  caProfileSubmitSelfSignedCMCFull  </servlet-name>
+      <servlet-class> com.netscape.cms.servlet.profile.ProfileSubmitCMCServlet  </servlet-class>
+             <init-param><param-name>  GetClientCert  </param-name>
+                         <param-value> false       </param-value> </init-param>
+             <init-param><param-name>  cert_request_type  </param-name>
+                         <param-value> cmc         </param-value> </init-param>
+             <init-param><param-name>  profileId   </param-name>
+                         <param-value> caFullCMCSelfSignedCert </param-value> </init-param>
+             <init-param><param-name>  AuthzMgr    </param-name>
+                         <param-value> BasicAclAuthz </param-value> </init-param>
+             <init-param><param-name>  authorityId  </param-name>
+                         <param-value> ca          </param-value> </init-param>
+             <init-param><param-name>  ID          </param-name>
+                         <param-value> caProfileSubmitSelfSignedCMCFull </param-value> </init-param>
+             <init-param><param-name>  templatePath  </param-name>
+                         <param-value> /ee/ca/ProfileSubmit.template </param-value> </init-param>
+             <init-param><param-name>  resourceID  </param-name>
+                         <param-value> certServer.ee.profile </param-value> </init-param>
+             <init-param><param-name>  interface   </param-name>
+                         <param-value> ee          </param-value> </init-param>
+   </servlet>
+
+   <servlet>
       <servlet-name>  caProfileList  </servlet-name>
       <servlet-class> com.netscape.cms.servlet.profile.ProfileListServlet  </servlet-class>
              <init-param><param-name>  GetClientCert  </param-name>
@@ -2284,6 +2307,11 @@
       <url-pattern>   /ee/ca/profileSubmitUserSignedCMCFull  </url-pattern>
    </servlet-mapping>
 
+   <servlet-mapping>
+      <servlet-name>  caProfileSubmitSelfSignedCMCFull  </servlet-name>
+      <url-pattern>   /ee/ca/profileSubmitSelfSignedCMCFull  </url-pattern>
+   </servlet-mapping>
+
    <servlet-mapping>  
       <servlet-name>  caProfileList  </servlet-name>
       <url-pattern>   /ee/ca/profileList  </url-pattern>
diff --git a/base/common/src/com/netscape/certsrv/authentication/IAuthManager.java b/base/common/src/com/netscape/certsrv/authentication/IAuthManager.java
index 21639e2..7d30d2e 100644
--- a/base/common/src/com/netscape/certsrv/authentication/IAuthManager.java
+++ b/base/common/src/com/netscape/certsrv/authentication/IAuthManager.java
@@ -33,6 +33,7 @@ public interface IAuthManager {
 
     /* standard credential for CMC request signing cert */
     public static final String CRED_CMC_SIGNING_CERT = "cmcSigningCert";
+    public static final String CRED_CMC_SELF_SIGNED = "cmcSelfSigned";
 
     /**
      * Standard credential for client cert's serial number from revocation.
diff --git a/base/common/src/com/netscape/certsrv/authentication/IAuthSubsystem.java b/base/common/src/com/netscape/certsrv/authentication/IAuthSubsystem.java
index e1ccc2d..9089527 100644
--- a/base/common/src/com/netscape/certsrv/authentication/IAuthSubsystem.java
+++ b/base/common/src/com/netscape/certsrv/authentication/IAuthSubsystem.java
@@ -119,6 +119,11 @@ public interface IAuthSubsystem extends ISubsystem {
     public static final String CMCAUTH_AUTHMGR_ID = "CMCAuth";
 
     /**
+     * Constant for CMC user-signed authentication manager ID.
+     */
+    public static final String CMC_USER_SIGNED_AUTH_AUTHMGR_ID = "CMCUserSignedAuth";
+
+    /**
      * Authenticate the given credentials using the given manager name.
      *
      * @param authCred The authentication credentials
diff --git a/base/common/src/com/netscape/certsrv/logging/AuditEvent.java b/base/common/src/com/netscape/certsrv/logging/AuditEvent.java
index 7a4aa9b..9d202df 100644
--- a/base/common/src/com/netscape/certsrv/logging/AuditEvent.java
+++ b/base/common/src/com/netscape/certsrv/logging/AuditEvent.java
@@ -126,8 +126,14 @@ public class AuditEvent implements IBundleLogEvent {
             "LOGGING_SIGNED_AUDIT_AUTH_SUCCESS_3";
     public final static String CERT_PROFILE_APPROVAL =
             "LOGGING_SIGNED_AUDIT_CERT_PROFILE_APPROVAL_4";
-    public final static String PROOF_OF_POSSESSION =
-            "LOGGING_SIGNED_AUDIT_PROOF_OF_POSSESSION_2";
+    public final static String PROOF_OF_POSSESSION_SUCCESS =
+            "LOGGING_SIGNED_AUDIT_PROOF_OF_POSSESSION_SUCCESS_2";
+    public final static String PROOF_OF_POSSESSION_FAILURE =
+            "LOGGING_SIGNED_AUDIT_PROOF_OF_POSSESSION_FAILURE_3";
+    public final static String CMC_PROOF_OF_IDENTIFICATION_SUCCESS =
+            "LOGGING_SIGNED_AUDIT_CMC_PROOF_OF_IDENTIFICATION_SUCCESS_2";
+    public final static String CMC_PROOF_OF_IDENTIFICATION_FAILURE =
+            "LOGGING_SIGNED_AUDIT_CMC_PROOF_OF_IDENTIFICATION_FAILURE_3";
 
     public final static String CRL_RETRIEVAL =
             "LOGGING_SIGNED_AUDIT_CRL_RETRIEVAL_3";
@@ -145,8 +151,10 @@ public class AuditEvent implements IBundleLogEvent {
             "LOGGING_SIGNED_AUDIT_OCSP_REMOVE_CA_REQUEST_PROCESSED_FAILURE_3";
     public final static String CMC_SIGNED_REQUEST_SIG_VERIFY =
             "LOGGING_SIGNED_AUDIT_CMC_SIGNED_REQUEST_SIG_VERIFY_5";
-    public final static String CMC_USER_SIGNED_REQUEST_SIG_VERIFY =
-            "LOGGING_SIGNED_AUDIT_CMC_USER_SIGNED_REQUEST_SIG_VERIFY_5";
+    public final static String CMC_USER_SIGNED_REQUEST_SIG_VERIFY_SUCCESS =
+            "LOGGING_SIGNED_AUDIT_CMC_USER_SIGNED_REQUEST_SIG_VERIFY_SUCCESS_5";
+    public final static String CMC_USER_SIGNED_REQUEST_SIG_VERIFY_FAILURE =
+            "LOGGING_SIGNED_AUDIT_CMC_USER_SIGNED_REQUEST_SIG_VERIFY_FAILURE_6";
 
     public final static String COMPUTE_RANDOM_DATA_REQUEST =
             "LOGGING_SIGNED_AUDIT_COMPUTE_RANDOM_DATA_REQUEST_2";
diff --git a/base/java-tools/src/com/netscape/cmstools/CMCRequest.java b/base/java-tools/src/com/netscape/cmstools/CMCRequest.java
index ac523ad..6e27cb1 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 d0e5c27..0057a1d 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 fd1d087..795c24b 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();
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 a72ce58..2128c1e 100644
--- a/base/server/cms/src/com/netscape/cms/authentication/CMCUserSignedAuth.java
+++ b/base/server/cms/src/com/netscape/cms/authentication/CMCUserSignedAuth.java
@@ -39,6 +39,7 @@ import java.util.Vector;
 import org.mozilla.jss.CryptoManager;
 import org.mozilla.jss.CryptoManager.NotInitializedException;
 import org.mozilla.jss.asn1.ASN1Util;
+import org.mozilla.jss.asn1.BIT_STRING;
 import org.mozilla.jss.asn1.INTEGER;
 import org.mozilla.jss.asn1.InvalidBERException;
 import org.mozilla.jss.asn1.OBJECT_IDENTIFIER;
@@ -66,6 +67,7 @@ import org.mozilla.jss.pkix.crmf.CertRequest;
 import org.mozilla.jss.pkix.crmf.CertTemplate;
 import org.mozilla.jss.pkix.primitive.AlgorithmIdentifier;
 import org.mozilla.jss.pkix.primitive.Name;
+import org.mozilla.jss.pkix.primitive.SubjectPublicKeyInfo;
 
 import com.netscape.certsrv.apps.CMS;
 import com.netscape.certsrv.authentication.AuthToken;
@@ -90,6 +92,9 @@ import com.netscape.cmsutil.crypto.CryptoUtil;
 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;
 import netscape.security.x509.X509CertInfo;
@@ -103,14 +108,15 @@ import netscape.security.x509.X509Key;
 /**
  * User Signed CMC authentication plug-in
  * note:
- *  - this version differs from CMCAuth in that it allows non-agent users
- *  to sign own cmc requests;  It is expected to be used with
- *  CMCUserSignedSubjectNameDefault and CMCUserSignedSubjectNameConstraint
- *  so that the resulting cert will bear the same subjectDN of that of the CMC
- *  signing cert
- *  - it originates from CMCAuth with modification for user-signed cmc
+ * - this version differs from CMCAuth in that it allows non-agent users
+ * to sign own cmc requests; It is expected to be used with
+ * CMCUserSignedSubjectNameDefault and CMCUserSignedSubjectNameConstraint
+ * so that the resulting cert will bear the same subjectDN of that of the CMC
+ * signing cert
+ * - it originates from CMCAuth with modification for user-signed cmc
+ *
  * @author cfu - user signed cmc authentication
- * <P>
+ *         <P>
  *
  * @version $Revision$, $Date$
  */
@@ -121,6 +127,12 @@ public class CMCUserSignedAuth implements IAuthManager, IExtendedPluginInfo,
     // default parameters //
     ////////////////////////
 
+    // only one request for self-signed
+    boolean selfSigned = false;
+    SubjectKeyIdentifierExtension selfsign_skiExtn = null;
+    PK11PubKey selfsign_pubK = null;
+    byte[] selfsign_digest = null;
+
     /////////////////////////////
     // IAuthManager parameters //
     /////////////////////////////
@@ -144,8 +156,7 @@ public class CMCUserSignedAuth implements IAuthManager, IExtendedPluginInfo,
      * for instances of this implementation can be configured through the
      * console.
      */
-    protected static String[] mConfigParams =
-            new String[] {};
+    protected static String[] mConfigParams = new String[] {};
 
     /* authentication plug-in values */
 
@@ -171,7 +182,7 @@ public class CMCUserSignedAuth implements IAuthManager, IExtendedPluginInfo,
 
         mExtendedPluginInfo
                 .add(IExtendedPluginInfo.HELP_TEXT +
-                    ";Authenticate the CMC request. The \"Authentication Instance ID\" must be named \"CMCUserSignedAuth\"");
+                        ";Authenticate the CMC request. The \"Authentication Instance ID\" must be named \"CMCUserSignedAuth\"");
         mExtendedPluginInfo.add(IExtendedPluginInfo.HELP_TOKEN +
                 ";configuration-authentication");
     }
@@ -185,10 +196,8 @@ public class CMCUserSignedAuth implements IAuthManager, IExtendedPluginInfo,
 
     /* signed audit parameters */
     private ILogger mSignedAuditLogger = CMS.getSignedAuditLogger();
-    private final static String SIGNED_AUDIT_ENROLLMENT_REQUEST_TYPE =
-            "enrollment";
-    private final static String SIGNED_AUDIT_REVOCATION_REQUEST_TYPE =
-            "revocation";
+    private final static String SIGNED_AUDIT_ENROLLMENT_REQUEST_TYPE = "enrollment";
+    private final static String SIGNED_AUDIT_REVOCATION_REQUEST_TYPE = "revocation";
 
     /////////////////////
     // default methods //
@@ -228,7 +237,8 @@ public class CMCUserSignedAuth implements IAuthManager, IExtendedPluginInfo,
      * <P>
      *
      * <ul>
-     * <li>signed.audit LOGGING_SIGNED_AUDIT_CMC_USER_SIGNED_REQUEST_SIG_VERIFY used when CMC (user-pre-signed) cert
+     * <li>signed.audit LOGGING_SIGNED_AUDIT_CMC_USER_SIGNED_REQUEST_SIG_VERIFY used when CMC
+     *  (user-pre-signed or self-signed) cert
      * requests or revocation requests are submitted and signature is verified
      * </ul>
      *
@@ -245,6 +255,7 @@ public class CMCUserSignedAuth implements IAuthManager, IExtendedPluginInfo,
     public IAuthToken authenticate(IAuthCredentials authCred) throws EMissingCredential, EInvalidCredentials,
             EBaseException {
         String method = "CMCUserSignedAuth: authenticate: ";
+        String msg = "";
         CMS.debug(method + "begins");
 
         String auditMessage = null;
@@ -273,40 +284,19 @@ public class CMCUserSignedAuth implements IAuthManager, IExtendedPluginInfo,
             if (cmc == null) {
                 CMS.debug(method + " Authentication failed. Missing CMC.");
 
-                // store a message in the signed audit log file
-                auditMessage = CMS.getLogMessage(
-                        AuditEvent.CMC_USER_SIGNED_REQUEST_SIG_VERIFY,
-                        auditSubjectID,
-                        ILogger.FAILURE,
-                        auditReqType,
-                        auditCertSubject,
-                        auditSignerInfo);
-
-                audit(auditMessage);
-
                 throw new EMissingCredential(CMS.getUserMessage(
                         "CMS_AUTHENTICATION_NULL_CREDENTIAL", CRED_CMC));
             }
 
             if (cmc.equals("")) {
-                log(ILogger.LL_FAILURE,
-                        "cmc : attempted login with empty CMC.");
-
-                // store a message in the signed audit log file
-                auditMessage = CMS.getLogMessage(
-                        AuditEvent.CMC_USER_SIGNED_REQUEST_SIG_VERIFY,
-                        auditSubjectID,
-                        ILogger.FAILURE,
-                        auditReqType,
-                        auditCertSubject,
-                        auditSignerInfo);
-
-                audit(auditMessage);
-
-                throw new EInvalidCredentials(CMS.getUserMessage(
-                        "CMS_AUTHENTICATION_INVALID_CREDENTIAL"));
+                msg = "attempted login with empty cert_request in authCred.";
+                CMS.debug(method + msg);
+
+                throw new EInvalidCredentials(msg);
             }
 
+            SessionContext auditContext = SessionContext.getExistingContext();
+
             // authenticate by checking CMC.
 
             // everything OK.
@@ -330,84 +320,88 @@ public class CMCUserSignedAuth implements IAuthManager, IExtendedPluginInfo,
                     asciiBASE64Blob = cmc;
 
                 byte[] cmcBlob = CMS.AtoB(asciiBASE64Blob);
-                ByteArrayInputStream cmcBlobIn = new
-                                                 ByteArrayInputStream(cmcBlob);
+                ByteArrayInputStream cmcBlobIn = new ByteArrayInputStream(cmcBlob);
 
                 org.mozilla.jss.pkix.cms.ContentInfo cmcReq =
-                        (org.mozilla.jss.pkix.cms.ContentInfo)
-                        org.mozilla.jss.pkix.cms.ContentInfo.getTemplate().decode(
+                        (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()) {
-                    // store a message in the signed audit log file
-                    auditMessage = CMS.getLogMessage(
-                            AuditEvent.CMC_USER_SIGNED_REQUEST_SIG_VERIFY,
-                            auditSubjectID,
-                            ILogger.FAILURE,
-                            auditReqType,
-                            auditCertSubject,
-                            auditSignerInfo);
 
-                    audit(auditMessage);
-
-                    // throw new ECMSGWException(CMSGWResources.NO_CMC_CONTENT);
-
-                    throw new EBaseException("NO_CMC_CONTENT");
+                    cmcBlobIn.close();
+                    msg = "cmc rquest content type is not ContentInfo.SIGNED_DATA";
+                    CMS.debug(msg);
+                    throw new EBaseException(msg);
                 }
 
-                SignedData cmcFullReq = (SignedData)
-                                        cmcReq.getInterpretedContent();
+                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);
-                String userid = "defUser";
-                String uid = "defUser";
+                boolean checkSignerInfo = cmc_config.getBoolean("cmc.signerInfo.verify", true);
                 if (checkSignerInfo) {
-                    IAuthToken userToken = verifySignerInfo(authToken, cmcFullReq);
+                    // selfSigned will be set in verifySignerInfo if applicable
+                    IAuthToken userToken = verifySignerInfo(auditContext, authToken, cmcFullReq);
                     if (userToken == null) {
-                        CMS.debug(method + " authenticate() userToken null");
-                        throw new EBaseException(method + " verifySignerInfo failure");
+                        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";
+                        } 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);
+                            }
+                        }
                     }
-                    userid = userToken.getInString("userid");
-                    uid = userToken.getInString("cn");
                 } else {
-                    CMS.debug(method + " authenticate() signerInfo verification bypassed");
-                }
-                // reset value of auditSignerInfo
-                if (uid != null) {
-                    auditSignerInfo = uid.trim();
+                    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);
 
                 OBJECT_IDENTIFIER id = ci.getContentType();
 
                 if (!id.equals(OBJECT_IDENTIFIER.id_cct_PKIData) ||
                         !ci.hasContent()) {
-                    // store a message in the signed audit log file
-                    auditMessage = CMS.getLogMessage(
-                            AuditEvent.CMC_USER_SIGNED_REQUEST_SIG_VERIFY,
-                            auditSubjectID,
-                            ILogger.FAILURE,
-                            auditReqType,
-                            auditCertSubject,
-                            auditSignerInfo);
-
-                    audit(auditMessage);
+                    msg = "request EncapsulatedContentInfo content type not OBJECT_IDENTIFIER.id_cct_PKIData";
+                    CMS.debug(method + msg);
 
-                    //  throw new ECMSGWException(
-                    // CMSGWResources.NO_PKIDATA);
-
-                    throw new EBaseException("NO_PKIDATA");
+                    throw new EBaseException(msg);
                 }
 
                 OCTET_STRING content = ci.getContent();
 
-                ByteArrayInputStream s = new
-                        ByteArrayInputStream(content.toByteArray());
+                ByteArrayInputStream s = new ByteArrayInputStream(content.toByteArray());
                 PKIData pkiData = (PKIData) (new PKIData.Template()).decode(s);
 
                 SEQUENCE reqSequence = pkiData.getReqSequence();
@@ -426,13 +420,12 @@ public class CMCUserSignedAuth implements IAuthManager, IExtendedPluginInfo,
 
                     if (controlSize > 0) {
                         for (int i = 0; i < controlSize; i++) {
-                            TaggedAttribute taggedAttribute =
-                                    (TaggedAttribute) controlSequence.elementAt(i);
+                            TaggedAttribute taggedAttribute = (TaggedAttribute) controlSequence.elementAt(i);
                             OBJECT_IDENTIFIER type = taggedAttribute.getType();
 
                             if (type.equals(
                                     OBJECT_IDENTIFIER.id_cmc_revokeRequest)) {
-/* TODO: user-signed revocation to be handled in next ticket
+                                /* TODO: user-signed revocation to be handled in next ticket
                                 // if( i ==1 ) {
                                 //     taggedAttribute.getType() ==
                                 //       OBJECT_IDENTIFIER.id_cmc_revokeRequest
@@ -479,10 +472,13 @@ public class CMCUserSignedAuth implements IAuthManager, IExtendedPluginInfo,
                                     Integer IntObject = Integer.valueOf((int) reasonCode);
                                     authToken.set(REASON_CODE, IntObject);
 
-                                    authToken.set("uid", uid);
-                                    authToken.set("userid", userid);
+
+                                    //authToken.set("uid", uid);
+                                    //authToken.set("userid", userid);
+
                                 }
-*/
+                                */
+
                             }
                         }
 
@@ -499,8 +495,7 @@ public class CMCUserSignedAuth implements IAuthManager, IExtendedPluginInfo,
 
                     for (int i = 0; i < numReqs; i++) {
                         // decode message.
-                        TaggedRequest taggedRequest =
-                                (TaggedRequest) reqSequence.elementAt(i);
+                        TaggedRequest taggedRequest = (TaggedRequest) reqSequence.elementAt(i);
 
                         TaggedRequest.Type type = taggedRequest.getType();
 
@@ -508,18 +503,15 @@ public class CMCUserSignedAuth implements IAuthManager, IExtendedPluginInfo,
                             CMS.debug(method + " type is PKCS10");
                             authToken.set("cert_request_type", "cmc-pkcs10");
 
-                            TaggedCertificationRequest tcr =
-                                    taggedRequest.getTcr();
+                            TaggedCertificationRequest tcr = taggedRequest.getTcr();
                             int p10Id = tcr.getBodyPartID().intValue();
 
                             reqIdArray[i] = String.valueOf(p10Id);
 
-                            CertificationRequest p10 =
-                                    tcr.getCertificationRequest();
+                            CertificationRequest p10 = tcr.getCertificationRequest();
 
                             // transfer to sun class
-                            ByteArrayOutputStream ostream =
-                                    new ByteArrayOutputStream();
+                            ByteArrayOutputStream ostream = new ByteArrayOutputStream();
 
                             p10.encode(ostream);
                             boolean sigver = true;
@@ -533,8 +525,8 @@ public class CMCUserSignedAuth implements IAuthManager, IExtendedPluginInfo,
                             try {
                                 cm = CryptoManager.getInstance();
                                 if (sigver == true) {
-                                    String tokenName =
-                                        CMS.getConfigStore().getString("ca.requestVerify.token", CryptoUtil.INTERNAL_TOKEN_NAME);
+                                    String tokenName = CMS.getConfigStore().getString("ca.requestVerify.token",
+                                            CryptoUtil.INTERNAL_TOKEN_NAME);
                                     savedToken = cm.getThreadToken();
                                     signToken = CryptoUtil.getCryptoToken(tokenName);
                                     if (!savedToken.getName().equals(signToken.getName())) {
@@ -543,65 +535,92 @@ public class CMCUserSignedAuth implements IAuthManager, IExtendedPluginInfo,
                                     }
                                 }
 
-                                PKCS10 pkcs10 =
-                                        new PKCS10(ostream.toByteArray(), sigver);
+                                PKCS10 pkcs10 = new PKCS10(ostream.toByteArray(), sigver);
+                                // reset value of auditCertSubject
+                                X500Name tempName = pkcs10.getSubjectName();
+                                CMS.debug(method + "request subject name=" + tempName.toString());
+                                if (tempName != null) {
+                                    auditCertSubject = tempName.toString().trim();
+                                    if (auditCertSubject.equals("")) {
+                                        auditCertSubject = ILogger.SIGNED_AUDIT_EMPTY_VALUE;
+                                    }
+                                    authToken.set(AuthToken.TOKEN_CERT_SUBJECT,
+                                            auditCertSubject/*tempName.toString()*/);
+                                }
+
+                                if (selfSigned) {
+                                    // prepare for checking SKI extension
+                                    try {
+                                        selfsign_skiExtn = (SubjectKeyIdentifierExtension) CryptoUtil
+                                                .getExtensionFromPKCS10(pkcs10, "SubjectKeyIdentifier");
+                                        if (selfsign_skiExtn != null)
+                                            CMS.debug(method + "SubjectKeyIdentifierExtension found:");
+                                        else {
+                                            msg = "missing SubjectKeyIdentifierExtension in request";
+                                            CMS.debug(method + msg);
+                                            throw new EBaseException(msg);
+                                        }
+                                    } catch (IOException e) {
+                                        msg = method + "SubjectKeyIdentifierExtension not found:" + e;
+                                        CMS.debug(msg);
+                                        throw new EBaseException(msg);
+                                    } catch (Exception e) {
+                                        msg = method + "SubjectKeyIdentifierExtension not found:" + e;
+                                        CMS.debug(msg);
+                                        throw new EBaseException(msg);
+                                    }
+
+                                    X509Key pubKey = pkcs10.getSubjectPublicKeyInfo();
+                                    PrivateKey.Type keyType = null;
+                                    String alg = pubKey.getAlgorithm();
+
+                                    if (alg.equals("RSA")) {
+                                        CMS.debug(method + "signing key alg=RSA");
+                                        keyType = PrivateKey.RSA;
+                                        selfsign_pubK = PK11PubKey.fromRaw(keyType, pubKey.getKey());
+                                    } else if (alg.equals("EC")) {
+                                        CMS.debug(method + "signing key alg=EC");
+                                        keyType = PrivateKey.EC;
+                                        byte publicKeyData[] = (pubKey).getEncoded();
+                                        selfsign_pubK = PK11ECPublicKey.fromSPKI(/*keyType,*/ publicKeyData);
+                                    } else {
+                                        msg = "unsupported signature algorithm: " + alg;
+                                        CMS.debug(method + msg);
+                                        throw new EInvalidCredentials(msg);
+                                    }
+                                    CMS.debug(method + "public key retrieved");
+                                    verifySelfSignedCMC(selfsign_signerInfo, id);
+
+                                } //selfSigned
 
                                 // xxx do we need to do anything else?
-                                X509CertInfo certInfo =
-                                        CMS.getDefaultX509CertInfo();
+                                X509CertInfo certInfo = CMS.getDefaultX509CertInfo();
 
                                 // fillPKCS10(certInfo,pkcs10,authToken,null);
 
                                 // authToken.set(
                                 //     pkcs10.getSubjectPublicKeyInfo());
 
-                                X500Name tempName = pkcs10.getSubjectName();
-
-                                // reset value of auditCertSubject
-                                if (tempName != null) {
-                                    auditCertSubject =
-                                            tempName.toString().trim();
-                                    if (auditCertSubject.equals("")) {
-                                        auditCertSubject =
-                                                ILogger.SIGNED_AUDIT_EMPTY_VALUE;
-                                    }
-                                    authToken.set(AuthToken.TOKEN_CERT_SUBJECT,
-                                              tempName.toString());
-                                }
-
+                                /*
                                 authToken.set("uid", uid);
                                 authToken.set("userid", userid);
+                                */
 
                                 certInfoArray[i] = certInfo;
                             } catch (Exception e) {
-                                // store a message in the signed audit log file
-                                auditMessage = CMS.getLogMessage(
-                                        AuditEvent.CMC_USER_SIGNED_REQUEST_SIG_VERIFY,
-                                        auditSubjectID,
-                                        ILogger.FAILURE,
-                                        auditReqType,
-                                        auditCertSubject,
-                                        auditSignerInfo);
-
-                                audit(auditMessage);
-
-                                //throw new ECMSGWException(
-                                //CMSGWResources.ERROR_PKCS101, e.toString());
-
                                 e.printStackTrace();
                                 throw new EBaseException(e.toString());
                             } finally {
-                                if ((sigver == true) && (tokenSwitched == true)){
+                                if ((sigver == true) && (tokenSwitched == true)) {
                                     cm.setThreadToken(savedToken);
                                 }
-                             }
+                            }
                         } else if (type.equals(TaggedRequest.CRMF)) {
 
                             CMS.debug(method + " type is CRMF");
                             authToken.set("cert_request_type", "cmc-crmf");
                             try {
-                                CertReqMsg crm =
-                                        taggedRequest.getCrm();
+                                CertReqMsg crm = taggedRequest.getCrm();
                                 CertRequest certReq = crm.getCertReq();
                                 INTEGER reqID = certReq.getCertReqId();
                                 reqIdArray[i] = reqID.toString();
@@ -609,70 +628,82 @@ public class CMCUserSignedAuth implements IAuthManager, IExtendedPluginInfo,
                                 Name name = template.getSubject();
 
                                 // xxx do we need to do anything else?
-                                X509CertInfo certInfo =
-                                        CMS.getDefaultX509CertInfo();
+                                X509CertInfo certInfo = CMS.getDefaultX509CertInfo();
 
                                 // reset value of auditCertSubject
                                 if (name != null) {
                                     String ss = name.getRFC1485();
 
+                                    CMS.debug(method + "setting auditCertSubject to: " + ss);
                                     auditCertSubject = ss;
                                     if (auditCertSubject.equals("")) {
-                                        auditCertSubject =
-                                                ILogger.SIGNED_AUDIT_EMPTY_VALUE;
+                                        auditCertSubject = ILogger.SIGNED_AUDIT_EMPTY_VALUE;
                                     }
 
                                     authToken.set(AuthToken.TOKEN_CERT_SUBJECT, ss);
-                                    authToken.set("uid", uid);
-                                    authToken.set("userid", userid);
+                                    //authToken.set("uid", uid);
+                                    //authToken.set("userid", userid);
                                 }
                                 certInfoArray[i] = certInfo;
-                            } catch (Exception e) {
-                                // store a message in the signed audit log file
-                                auditMessage = CMS.getLogMessage(
-                                        AuditEvent.CMC_USER_SIGNED_REQUEST_SIG_VERIFY,
-                                        auditSubjectID,
-                                        ILogger.FAILURE,
-                                        auditReqType,
-                                        auditCertSubject,
-                                        auditSignerInfo);
 
-                                audit(auditMessage);
+                                if (selfSigned) {
+                                    selfsign_skiExtn =
+                                            (SubjectKeyIdentifierExtension) CryptoUtil
+                                            .getExtensionFromCertTemplate(template, PKIXExtensions.SubjectKey_Id);
+                                    if (selfsign_skiExtn != null) {
+                                        CMS.debug(method +
+                                                "SubjectKeyIdentifierExtension found");
+                                    } else {
+                                        CMS.debug(method +
+                                                "SubjectKeyIdentifierExtension not found");
+                                    }
+
+                                    // get public key for verifying signature later
+                                    SubjectPublicKeyInfo pkinfo = template.getPublicKey();
+                                    PrivateKey.Type keyType = null;
+                                    String alg = pkinfo.getAlgorithm();
+                                    BIT_STRING bitString = pkinfo.getSubjectPublicKey();
+                                    byte[] publicKeyData = bitString.getBits();
+                                    if (alg.equals("RSA")) {
+                                        CMS.debug(method + "signing key alg=RSA");
+                                        keyType = PrivateKey.RSA;
+                                        selfsign_pubK = PK11PubKey.fromRaw(keyType, publicKeyData);
+                                    } else if (alg.equals("EC")) {
+                                        CMS.debug(method + "signing key alg=EC");
+                                        keyType = PrivateKey.EC;
+                                        selfsign_pubK = PK11ECPublicKey.fromSPKI(/*keyType,*/ publicKeyData);
+                                    } else {
+                                        msg = "unsupported signature algorithm: " + alg;
+                                        CMS.debug(method + msg);
+                                        throw new EInvalidCredentials(msg);
+                                    }
+                                    CMS.debug(method + "public key retrieved");
 
-                                //throw new ECMSGWException(
-                                //CMSGWResources.ERROR_PKCS101, e.toString());
+                                    verifySelfSignedCMC(selfsign_signerInfo, id);
+                                } //selfSigned
 
+                            } catch (Exception e) {
                                 e.printStackTrace();
+                                cmcBlobIn.close();
+                                s.close();
                                 throw new EBaseException(e.toString());
                             }
                         }
 
-                        // authToken.set(AgentAuthentication.CRED_CERT, new
-                        //     com.netscape.certsrv.usrgrp.Certificates(
-                        //     x509Certs));
                     }
                 }
+
+                authToken.set("uid", uid);
+                authToken.set("userid", userid);
             } catch (Exception e) {
                 CMS.debug(method + e);
-                // store a message in the signed audit log file
-                auditMessage = CMS.getLogMessage(
-                        AuditEvent.CMC_USER_SIGNED_REQUEST_SIG_VERIFY,
-                        auditSubjectID,
-                        ILogger.FAILURE,
-                        auditReqType,
-                        auditCertSubject,
-                        auditSignerInfo);
-
-                audit(auditMessage);
-
                 //Debug.printStackTrace(e);
-                throw new EInvalidCredentials(CMS.getUserMessage(
-                        "CMS_AUTHENTICATION_INVALID_CREDENTIAL"));
+                throw new EInvalidCredentials(e.toString());
             }
 
             // store a message in the signed audit log file
             auditMessage = CMS.getLogMessage(
-                    AuditEvent.CMC_USER_SIGNED_REQUEST_SIG_VERIFY,
+                    AuditEvent.CMC_USER_SIGNED_REQUEST_SIG_VERIFY_SUCCESS,
                     auditSubjectID,
                     ILogger.SUCCESS,
                     auditReqType,
@@ -687,12 +718,13 @@ public class CMCUserSignedAuth implements IAuthManager, IExtendedPluginInfo,
             CMS.debug(method + eAudit1);
             // store a message in the signed audit log file
             auditMessage = CMS.getLogMessage(
-                    AuditEvent.CMC_USER_SIGNED_REQUEST_SIG_VERIFY,
+                    AuditEvent.CMC_USER_SIGNED_REQUEST_SIG_VERIFY_FAILURE,
                     auditSubjectID,
                     ILogger.FAILURE,
                     auditReqType,
                     auditCertSubject,
-                    auditSignerInfo);
+                    auditSignerInfo,
+                    eAudit1.toString());
 
             audit(auditMessage);
 
@@ -702,12 +734,13 @@ public class CMCUserSignedAuth implements IAuthManager, IExtendedPluginInfo,
             CMS.debug(method + eAudit2);
             // store a message in the signed audit log file
             auditMessage = CMS.getLogMessage(
-                    AuditEvent.CMC_USER_SIGNED_REQUEST_SIG_VERIFY,
+                    AuditEvent.CMC_USER_SIGNED_REQUEST_SIG_VERIFY_FAILURE,
                     auditSubjectID,
                     ILogger.FAILURE,
                     auditReqType,
                     auditCertSubject,
-                    auditSignerInfo);
+                    auditSignerInfo,
+                    eAudit2.toString());
 
             audit(auditMessage);
 
@@ -717,17 +750,70 @@ public class CMCUserSignedAuth implements IAuthManager, IExtendedPluginInfo,
             CMS.debug(method + eAudit3);
             // store a message in the signed audit log file
             auditMessage = CMS.getLogMessage(
-                    AuditEvent.CMC_USER_SIGNED_REQUEST_SIG_VERIFY,
+                    AuditEvent.CMC_USER_SIGNED_REQUEST_SIG_VERIFY_FAILURE,
                     auditSubjectID,
                     ILogger.FAILURE,
                     auditReqType,
                     auditCertSubject,
-                    auditSignerInfo);
+                    auditSignerInfo,
+                    eAudit3.toString());
 
             audit(auditMessage);
 
             // rethrow the specific exception to be handled later
             throw eAudit3;
+        } catch (Exception eAudit4) {
+            CMS.debug(method + eAudit4);
+            // store a message in the signed audit log file
+            auditMessage = CMS.getLogMessage(
+                    AuditEvent.CMC_USER_SIGNED_REQUEST_SIG_VERIFY_FAILURE,
+                    auditSubjectID,
+                    ILogger.FAILURE,
+                    auditReqType,
+                    auditCertSubject,
+                    auditSignerInfo,
+                    eAudit4.toString());
+
+            audit(auditMessage);
+
+            // rethrow the specific exception to be handled later
+            throw eAudit4;
+        }
+    }
+
+    /*
+    * verifySelfSignedCMC() verifies the following
+    * a. the required (per RFC 5272) SKI extension in the request matches that in the
+    *    SignerIdentifier
+    * b. the signature in the request
+    */
+    protected void verifySelfSignedCMC(
+            org.mozilla.jss.pkix.cms.SignerInfo signerInfo,
+            OBJECT_IDENTIFIER id)
+            throws EBaseException {
+        String method = "CMCUserSignedAuth: verifySelfSignedCMC: ";
+        CMS.debug(method + "begins");
+        try {
+            SignerIdentifier sid = signerInfo.getSignerIdentifier();
+            OCTET_STRING subjKeyId = sid.getSubjectKeyIdentifier();
+            KeyIdentifier keyIdObj =
+                    (KeyIdentifier) selfsign_skiExtn.get(SubjectKeyIdentifierExtension.KEY_ID);
+            boolean match = CryptoUtil.compare(subjKeyId.toByteArray(), keyIdObj.getIdentifier());
+            if (match) {
+                CMS.debug(method +
+                        " SignerIdentifier SUBJECT_KEY_IDENTIFIER matches SKI of request");
+            } else {
+                CMS.debug(method +
+                        " SignerIdentifier SUBJECT_KEY_IDENTIFIER failed to match");
+                throw new EInvalidCredentials(CMS.getUserMessage("CMS_AUTHENTICATION_INVALID_CREDENTIAL"));
+            }
+            // verify sig using public key in request
+            CMS.debug(method + "verifying request signature with public key");
+            signerInfo.verify(selfsign_digest, id, selfsign_pubK);
+            CMS.debug(method + " signature verified");
+        } catch (Exception e) {
+            CMS.debug(method + e.toString());
+            throw new EBaseException(method + e.toString());
         }
     }
 
@@ -825,10 +911,24 @@ public class CMCUserSignedAuth implements IAuthManager, IExtendedPluginInfo,
                 level, "CMC User Signed Authentication: " + msg);
     }
 
-    protected IAuthToken verifySignerInfo(AuthToken authToken, SignedData cmcFullReq) throws EBaseException {
+    /**
+     * User-signed CMC requests can be signed in two ways:
+     * a. signed with previously issued user signing cert
+     * b. self-signed with the private key paired with the public key in
+     * the request
+     *
+     * In case "a", the resulting authToke would contain
+     * (IAuthManager.CRED_CMC_SIGNING_CERT, signing cert serial number)
+     * In case "b", the resulting authToke would not contain the attribute
+     * IAuthManager.CRED_CMC_SIGNING_CERT
+     */
+    protected IAuthToken verifySignerInfo(
+            SessionContext auditContext, // to capture info in case of failure
+            AuthToken authToken,
+            SignedData cmcFullReq)
+            throws EBaseException {
         String method = "CMCUserSignedAuth: verifySignerInfo: ";
         CMS.debug(method + "begins");
-
         EncapsulatedContentInfo ci = cmcFullReq.getContentInfo();
         OBJECT_IDENTIFIER id = ci.getContentType();
         OCTET_STRING content = ci.getContent();
@@ -849,13 +949,10 @@ public class CMCUserSignedAuth implements IAuthManager, IExtendedPluginInfo,
             //if request key is used for signing, there MUST be only one signerInfo
             //object in the signedData object.
             for (int i = 0; i < numDig; i++) {
-                AlgorithmIdentifier dai =
-                        (AlgorithmIdentifier) dais.elementAt(i);
-                String name =
-                        DigestAlgorithm.fromOID(dai.getOID()).toString();
+                AlgorithmIdentifier dai = (AlgorithmIdentifier) dais.elementAt(i);
+                String name = DigestAlgorithm.fromOID(dai.getOID()).toString();
 
-                MessageDigest md =
-                        MessageDigest.getInstance(name);
+                MessageDigest md = MessageDigest.getInstance(name);
 
                 byte[] digest = md.digest(content.toByteArray());
 
@@ -867,6 +964,7 @@ public class CMCUserSignedAuth implements IAuthManager, IExtendedPluginInfo,
 
             for (int i = 0; i < numSis; i++) {
                 org.mozilla.jss.pkix.cms.SignerInfo si = (org.mozilla.jss.pkix.cms.SignerInfo) sis.elementAt(i);
+                //selfsign_SignerInfo = (org.mozilla.jss.pkix.cms.SignerInfo) sis.elementAt(i);
 
                 String name = si.getDigestAlgorithm().toString();
                 byte[] digest = digs.get(name);
@@ -879,11 +977,14 @@ public class CMCUserSignedAuth implements IAuthManager, IExtendedPluginInfo,
                     digest = md.digest(ostream.toByteArray());
 
                 }
+
                 // signed  by  previously certified signature key
                 SignerIdentifier sid = si.getSignerIdentifier();
-                // TODO: need to handle signing key being the matching key from
-                // the request
                 if (sid.getType().equals(SignerIdentifier.ISSUER_AND_SERIALNUMBER)) {
+                    CMS.debug(method + "SignerIdentifier type: ISSUER_AND_SERIALNUMBER");
+                    selfSigned = false;
+                    CMS.debug(method + "selfSigned is false");
+
                     IssuerAndSerialNumber issuerAndSerialNumber = sid.getIssuerAndSerialNumber();
                     // find from the certs in the signedData
                     java.security.cert.X509Certificate cert = null;
@@ -899,14 +1000,12 @@ public class CMCUserSignedAuth implements IAuthManager, IExtendedPluginInfo,
                             Name issuer = certI.getIssuer();
 
                             byte[] issuerB = ASN1Util.encode(issuer);
-CMS.debug(method + "issuer = " + new String(issuerB));
                             INTEGER sn = certI.getSerialNumber();
                             // if this cert is the signer cert, not a cert in the chain
                             if (new String(issuerB).equals(new String(
                                     ASN1Util.encode(issuerAndSerialNumber.getIssuer())))
                                     && sn.toString().equals(issuerAndSerialNumber.getSerialNumber().toString())) {
-                                ByteArrayOutputStream os = new
-                                        ByteArrayOutputStream();
+                                ByteArrayOutputStream os = new ByteArrayOutputStream();
 
                                 certJss.encode(os);
                                 certByteArray = os.toByteArray();
@@ -919,13 +1018,23 @@ CMS.debug(method + "issuer = " + new String(issuerB));
 
                             }
                         }
+
                         CMS.debug(method + "start checking signature");
+                        String CN = null;
                         if (cert == null) {
                             // find from certDB
                             CMS.debug(method + "verifying signature");
                             si.verify(digest, id);
                         } else {
                             CMS.debug(method + "found signing cert... verifying");
+
+                            //capture auditSubjectID first in case of failure
+                            netscape.security.x509.X500Name tempPrincipal =
+                                    (X500Name) x509Certs[0].getSubjectDN();
+                            CN = tempPrincipal.getCommonName(); //tempToken.get("userid");
+                            CMS.debug(method + " Principal name = " + CN);
+                            auditContext.put(SessionContext.USER_ID, CN);
+
                             PublicKey signKey = cert.getPublicKey();
                             PrivateKey.Type keyType = null;
                             String alg = signKey.getAlgorithm();
@@ -942,21 +1051,24 @@ CMS.debug(method + "issuer = " + new String(issuerB));
                                 pubK = PK11ECPublicKey.fromSPKI(/*keyType,*/ publicKeyData);
                             } else {
                                 CMS.debug(method + "unsupported signature algorithm: " + alg);
-                                throw new EInvalidCredentials(CMS.getUserMessage("CMS_AUTHENTICATION_INVALID_CREDENTIAL"));
+                                s.close();
+                                throw new EInvalidCredentials(
+                                        CMS.getUserMessage("CMS_AUTHENTICATION_INVALID_CREDENTIAL"));
                             }
 
-                            String tokenName =
-                                CMS.getConfigStore().getString("ca.requestVerify.token", CryptoUtil.INTERNAL_TOKEN_NAME);
+                            String tokenName = CMS.getConfigStore().getString("ca.requestVerify.token",
+                                    CryptoUtil.INTERNAL_TOKEN_NAME);
                             // by default JSS will use internal crypto token
                             if (!CryptoUtil.isInternalToken(tokenName)) {
                                 savedToken = cm.getThreadToken();
                                 signToken = CryptoUtil.getCryptoToken(tokenName);
-                                if(signToken != null) {
+                                if (signToken != null) {
                                     cm.setThreadToken(signToken);
                                     tokenSwitched = true;
-                                    CMS.debug(method + "verifySignerInfo token switched:"+ tokenName);
+                                    CMS.debug(method + "verifySignerInfo token switched:" + tokenName);
                                 } else {
-                                    CMS.debug(method + "verifySignerInfo token not found:"+ tokenName+ ", trying internal");
+                                    CMS.debug(method + "verifySignerInfo token not found:" + tokenName
+                                            + ", trying internal");
                                 }
                             }
 
@@ -967,6 +1079,7 @@ CMS.debug(method + "issuer = " + new String(issuerB));
                         // verify signer's certificate using the revocator
                         if (!cm.isCertValid(certByteArray, true, CryptoManager.CertUsage.SSLClient)) {
                             CMS.debug(method + "CMC signature failed to be verified");
+                            s.close();
                             throw new EInvalidCredentials(CMS.getUserMessage("CMS_AUTHENTICATION_INVALID_CREDENTIAL"));
                         } else {
                             CMS.debug(method + "CMC signature verified; but signer not yet;");
@@ -974,23 +1087,38 @@ CMS.debug(method + "issuer = " + new String(issuerB));
                         // At this point, the signature has been verified;
 
                         IAuthToken tempToken = new AuthToken(null);
+/*
                         netscape.security.x509.X500Name tempPrincipal = (X500Name) x509Certs[0].getSubjectDN();
                         String CN = tempPrincipal.getCommonName(); //tempToken.get("userid");
                         CMS.debug(method + " Principal name = " + CN);
+*/
 
                         BigInteger certSerial = x509Certs[0].getSerialNumber();
                         CMS.debug(method + " verified cert serial=" + certSerial.toString());
                         authToken.set(IAuthManager.CRED_CMC_SIGNING_CERT, certSerial.toString());
                         tempToken.set("cn", CN);
 
+                        s.close();
                         return tempToken;
 
+                    } else {
+                        CMS.debug(method + "no certificate found in cmcFullReq");
                     }
-
+                } else if (sid.getType().equals(SignerIdentifier.SUBJECT_KEY_IDENTIFIER)) {
+                    CMS.debug(method + "SignerIdentifier type: SUBJECT_KEY_IDENTIFIER");
+                    CMS.debug(method + "selfSigned is true");
+                    selfSigned = true;
+                    selfsign_digest = digest;
+
+                    IAuthToken tempToken = new AuthToken(null);
+                    authToken.set(IAuthManager.CRED_CMC_SELF_SIGNED, "true");
+                    s.close();
+                    return tempToken;
                 } else {
                     CMS.debug(method + "unsupported SignerIdentifier type");
                 }
-            }
+            } //for
+
         } catch (InvalidBERException e) {
             CMS.debug(method + e.toString());
         } catch (IOException e) {
@@ -1001,7 +1129,7 @@ CMS.debug(method + "issuer = " + new String(issuerB));
             CMS.debug(method + e.toString());
             throw new EInvalidCredentials(CMS.getUserMessage("CMS_AUTHENTICATION_INVALID_CREDENTIAL"));
         } finally {
-            if ((tokenSwitched == true) && (savedToken != null)){
+            if ((tokenSwitched == true) && (savedToken != null)) {
                 cm.setThreadToken(savedToken);
                 CMS.debug(method + "verifySignerInfo token restored");
             }
@@ -1123,8 +1251,7 @@ CMS.debug(method + "issuer = " + new String(issuerB));
         SessionContext auditContext = SessionContext.getExistingContext();
 
         if (auditContext != null) {
-            subjectID = (String)
-                    auditContext.get(SessionContext.USER_ID);
+            subjectID = (String) auditContext.get(SessionContext.USER_ID);
 
             if (subjectID != null) {
                 subjectID = subjectID.trim();
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 7d52fc8..708ef2d 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
@@ -110,6 +110,8 @@ import netscape.security.x509.CertificateVersion;
 import netscape.security.x509.CertificateX509Key;
 import netscape.security.x509.Extension;
 import netscape.security.x509.Extensions;
+import netscape.security.x509.PKIXExtensions;
+import netscape.security.x509.SubjectKeyIdentifierExtension;
 import netscape.security.x509.X500Name;
 import netscape.security.x509.X509CertImpl;
 import netscape.security.x509.X509CertInfo;
@@ -776,7 +778,8 @@ public abstract class EnrollProfile extends BasicProfile
                         }
                     } else if (id_cmc_identityProofV2 && (attr != null)) {
                         // either V2 or not V2; can't be both
-                        CMS.debug(method + "not pre-signed CMC request; calling verifyIdentityProofV2;");
+                        CMS.debug(method +
+                                "not pre-signed CMC request; calling verifyIdentityProofV2;");
                         if (!id_cmc_identification) {
                             SEQUENCE bpids = getRequestBpids(reqSeq);
                             context.put("identification", bpids);
@@ -788,7 +791,7 @@ public abstract class EnrollProfile extends BasicProfile
                                             msg);
                         }
 
-                        boolean valid = verifyIdentityProofV2(attr, ident_s,
+                        boolean valid = verifyIdentityProofV2(context, attr, ident_s,
                                 reqSeq);
                         if (!valid) {
                             SEQUENCE bpids = getRequestBpids(reqSeq);
@@ -877,6 +880,11 @@ public abstract class EnrollProfile extends BasicProfile
                 String configName = "cmc.popLinkWitnessRequired";
                 CMS.debug(method + "getting :" + configName);
                 popLinkWitnessRequired = CMS.getConfigStore().getBoolean(configName, false);
+                if (popLinkWitnessRequired) {
+                    CMS.debug(method + "popLinkWitness(V2) required");
+                } else {
+                    CMS.debug(method + "popLinkWitness(V2) not required");
+                }
             } catch (Exception e) {
                 // unlikely to get here
                 msg = method + " Failed to retrieve cmc.popLinkWitnessRequired";
@@ -1441,22 +1449,44 @@ public abstract class EnrollProfile extends BasicProfile
      * @author cfu
      */
     private boolean verifyIdentityProofV2(
+            SessionContext sessionContext,
             TaggedAttribute attr,
             UTF8String ident,
             SEQUENCE reqSeq) {
         String method = "EnrollProfile:verifyIdentityProofV2: ";
+        String msg = "";
         CMS.debug(method + " begins");
+        boolean verified = false;
+        String auditMessage = method;
+
         if ((attr == null) ||
                 (ident == null) ||
                 (reqSeq == null)) {
             CMS.debug(method + "method parameters cannot be null");
+            // this is internal error
             return false;
         }
 
         String ident_string = ident.toString();
+        String auditAttemptedCred = null;
+//cfu test only
+            auditMessage = CMS.getLogMessage(
+                    AuditEvent.CMC_PROOF_OF_IDENTIFICATION_FAILURE,
+                    auditAttemptedCred,
+                    ILogger.FAILURE,
+                    method + msg);
+            audit(auditMessage);
 
         SET vals = attr.getValues(); // getting the IdentityProofV2 structure
         if (vals.size() < 1) {
+            msg = " invalid TaggedAttribute in request";
+            CMS.debug(method + msg);
+            auditMessage = CMS.getLogMessage(
+                    AuditEvent.CMC_PROOF_OF_IDENTIFICATION_FAILURE,
+                    auditAttemptedCred,
+                    ILogger.FAILURE,
+                    method + msg);
+            audit(auditMessage);
             return false;
         }
 
@@ -1464,18 +1494,33 @@ public abstract class EnrollProfile extends BasicProfile
         ISharedToken tokenClass = getSharedTokenClass(configName);
 
         if (tokenClass == null) {
-            CMS.debug(method + " Failed to retrieve shared secret plugin class");
+            msg = " Failed to retrieve shared secret plugin class";
+            CMS.debug(method + msg);
+            auditMessage = CMS.getLogMessage(
+                    AuditEvent.CMC_PROOF_OF_IDENTIFICATION_FAILURE,
+                    auditAttemptedCred,
+                    ILogger.FAILURE,
+                    method + msg);
+            audit(auditMessage);
             return false;
         }
 
         String token = null;
-        if (ident_string != null)
+        if (ident_string != null) {
+            auditAttemptedCred = ident_string;
             token = tokenClass.getSharedToken(ident_string);
-        else
+        } else
             token = tokenClass.getSharedToken(mCMCData);
 
         if (token == null) {
-            CMS.debug(method + " Failed to retrieve shared secret");
+            msg = " Failed to retrieve shared secret";
+            CMS.debug(method + msg);
+            auditMessage = CMS.getLogMessage(
+                    AuditEvent.CMC_PROOF_OF_IDENTIFICATION_FAILURE,
+                    auditAttemptedCred,
+                    ILogger.FAILURE,
+                    method + msg);
+            audit(auditMessage);
             return false;
         }
 
@@ -1493,26 +1538,63 @@ public abstract class EnrollProfile extends BasicProfile
 
             OCTET_STRING witness = idV2val.getWitness();
             if (witness == null) {
-                CMS.debug(method + " witness reurned by idV2val.getWitness is null");
-                return false;
+                msg = " witness reurned by idV2val.getWitness is null";
+                CMS.debug(method + msg);
+                throw new EBaseException(msg);
             }
 
             byte[] witness_bytes = witness.toByteArray();
             byte[] request_bytes = ASN1Util.encode(reqSeq); // PKIData reqSequence field
-            return verifyDigest(
+            verified = verifyDigest(
                     (ident_string != null) ? (token + ident_string).getBytes() : token.getBytes(),
                     request_bytes,
                     witness_bytes,
                     hashAlg, macAlg);
+
+            String authMgrID =
+                    (String) sessionContext.get(SessionContext.AUTH_MANAGER_ID);
+            String auditSubjectID = null;
+
+            if (verified) {
+                // update auditSubjectID
+                if (sessionContext != null) {
+                    auditSubjectID = (String)
+                            sessionContext.get(SessionContext.USER_ID);
+                    CMS.debug(method + "current auditSubjectID was:"+ auditSubjectID);
+                    CMS.debug(method + "identity verified. Updating auditSubjectID");
+                    CMS.debug(method + "updated auditSubjectID is:"+ ident_string);
+                    auditSubjectID = ident_string;
+                    sessionContext.put(SessionContext.USER_ID, auditSubjectID);
+                } else { //very unlikely
+                    CMS.debug(method + "sessionContext null; cannot update auditSubjectID");
+                }
+
+                auditMessage = CMS.getLogMessage(
+                        AuditEvent.CMC_PROOF_OF_IDENTIFICATION_SUCCESS,
+                        auditSubjectID,
+                        ILogger.SUCCESS);
+                audit(auditMessage);
+            } else {
+                throw new EBaseException("failed to verify");
+            }
+            return verified;
         } catch (Exception e) {
             CMS.debug(method + " Failed with Exception: " + e.toString());
+            auditMessage = CMS.getLogMessage(
+                    AuditEvent.CMC_PROOF_OF_IDENTIFICATION_FAILURE,
+                    auditAttemptedCred,
+                    ILogger.FAILURE,
+                    method + e.toString());
+            audit(auditMessage);
             return false;
         }
 
     } // verifyIdentityProofV2
 
-    private boolean verifyIdentityProof(TaggedAttribute attr, SEQUENCE reqSeq) {
+    private boolean verifyIdentityProof(
+            TaggedAttribute attr, SEQUENCE reqSeq) {
         String method = "verifyIdentityProof: ";
+        boolean verified = false;
 
         SET vals = attr.getValues();
         if (vals.size() < 1)
@@ -1537,7 +1619,11 @@ public abstract class EnrollProfile extends BasicProfile
             byte[] b = ostr.toByteArray();
             byte[] text = ASN1Util.encode(reqSeq);
 
-            return verifyDigest(token.getBytes(), text, b);
+            verified = verifyDigest(token.getBytes(), text, b);
+            if (verified) {// update auditSubjectID
+                //placeholder. Should probably just disable this v1 method
+            }
+            return verified;
     }
 
     public void fillTaggedRequest(Locale locale, TaggedRequest tagreq, X509CertInfo info,
@@ -1592,13 +1678,21 @@ public abstract class EnrollProfile extends BasicProfile
 
                 p10.encode(ostream);
                 PKCS10 pkcs10 = new PKCS10(ostream.toByteArray(), sigver);
+                if (sigver) {
+                    auditMessage = CMS.getLogMessage(
+                            AuditEvent.PROOF_OF_POSSESSION_SUCCESS,
+                            auditSubjectID,
+                            ILogger.SUCCESS);
+                    audit(auditMessage);
+                }
 
                 req.setExtData("bodyPartId", tcr.getBodyPartID());
                 fillPKCS10(locale, pkcs10, info, req);
             } catch (Exception e) {
                 CMS.debug(method + e);
                 // this will throw
-                popFailed(locale, auditSubjectID, auditMessage, e);
+                if (sigver)
+                    popFailed(locale, auditSubjectID, auditMessage, e);
             }  finally {
                 if ((sigver == true) && (tokenSwitched == true)){
                     cm.setThreadToken(savedToken);
@@ -1787,8 +1881,9 @@ public abstract class EnrollProfile extends BasicProfile
     public void fillCertReqMsg(Locale locale, CertReqMsg certReqMsg, X509CertInfo info,
             IRequest req)
             throws EProfileException {
+        String method = "EnrollProfile: fillCertReqMsg: ";
         try {
-            CMS.debug("Start parseCertReqMsg ");
+            CMS.debug(method + "Start parseCertReqMsg ");
             CertRequest certReq = certReqMsg.getCertReq();
             req.setExtData("bodyPartId", certReq.getCertReqId());
             // handle PKIArchiveOption (key archival)
@@ -1897,12 +1992,20 @@ public abstract class EnrollProfile extends BasicProfile
                     extensions = new CertificateExtensions();
                 int numexts = certTemplate.numExtensions();
 
+                /*
+                 * there seems to be an issue with constructor in Extension
+                 * when feeding SubjectKeyIdentifierExtension;
+                 * Special-case it
+                 */
+                OBJECT_IDENTIFIER SKIoid =
+                        new OBJECT_IDENTIFIER(PKIXExtensions.SubjectKey_Id.toString());
                 for (int j = 0; j < numexts; j++) {
                     org.mozilla.jss.pkix.cert.Extension jssext =
                             certTemplate.extensionAt(j);
                     boolean isCritical = jssext.getCritical();
                     org.mozilla.jss.asn1.OBJECT_IDENTIFIER jssoid =
                             jssext.getExtnId();
+                    CMS.debug(method + "found extension:" + jssoid.toString());
                     long[] numbers = jssoid.getNumbers();
                     int[] oidNumbers = new int[numbers.length];
 
@@ -1919,8 +2022,14 @@ public abstract class EnrollProfile extends BasicProfile
                     jssvalue.encode(jssvalueout);
                     byte[] extValue = jssvalueout.toByteArray();
 
-                    Extension ext =
-                            new Extension(oid, isCritical, extValue);
+                    Extension ext = null;
+                    if (jssoid.equals(SKIoid)) {
+                        CMS.debug(method + "found SUBJECT_KEY_IDENTIFIER extension");
+                        ext = new SubjectKeyIdentifierExtension(false,
+                                jssext.getExtnValue().toByteArray());
+                    } else {
+                        new Extension(oid, isCritical, extValue);
+                    }
 
                     extensions.parseExtension(ext);
                 }
@@ -2042,12 +2151,12 @@ public abstract class EnrollProfile extends BasicProfile
                     DerInputStream extIn = new DerInputStream(extB);
                     CertificateExtensions exts = new CertificateExtensions(extIn);
                     if (exts != null) {
-                        CMS.debug(method + "Set extensions " + exts);
+                        CMS.debug(method + "PKCS10 found extensions " + exts);
                         // info.set(X509CertInfo.EXTENSIONS, exts);
                         req.setExtData(REQUEST_EXTENSIONS, exts);
                     }
                 } else {
-                    CMS.debug(method + "PKCS10 extension Not Found");
+                    CMS.debug(method + "PKCS10 no extension found");
                 }
             }
 
@@ -2406,7 +2515,7 @@ public abstract class EnrollProfile extends BasicProfile
         String method = "EnrollProfile: verifyPOP: ";
         CMS.debug(method + "for signing keys begins.");
 
-        String auditMessage = null;
+        String auditMessage = method;
         String auditSubjectID = auditSubjectID();
 
         if (!certReqMsg.hasPop()) {
@@ -2435,7 +2544,7 @@ public abstract class EnrollProfile extends BasicProfile
 
             // store a message in the signed audit log file
             auditMessage = CMS.getLogMessage(
-                    AuditEvent.PROOF_OF_POSSESSION,
+                    AuditEvent.PROOF_OF_POSSESSION_SUCCESS,
                     auditSubjectID,
                     ILogger.SUCCESS);
             audit(auditMessage);
@@ -2446,19 +2555,21 @@ public abstract class EnrollProfile extends BasicProfile
         CMS.debug(method + "done.");
     }
 
-    private void popFailed(Locale locale, String auditSubjectID, String auditMessage)
+    private void popFailed(Locale locale, String auditSubjectID, String msg)
             throws EProfileException {
-        popFailed(locale, auditSubjectID, auditMessage, null);
+        popFailed(locale, auditSubjectID, msg, null);
     }
-    private void popFailed(Locale locale, String auditSubjectID, String auditMessage, Exception e)
+    private void popFailed(Locale locale, String auditSubjectID, String msg, Exception e)
             throws EProfileException {
 
+            if (e != null)
+                msg = msg + e.toString();
             // store a message in the signed audit log file
-            auditMessage = CMS.getLogMessage(
-                    AuditEvent.PROOF_OF_POSSESSION,
+            String auditMessage = CMS.getLogMessage(
+                    AuditEvent.PROOF_OF_POSSESSION_FAILURE,
                     auditSubjectID,
-                    ILogger.FAILURE);
-
+                    ILogger.FAILURE,
+                    msg);
             audit(auditMessage);
 
             if (e != null) {
diff --git a/base/server/cms/src/com/netscape/cms/profile/def/CAEnrollDefault.java b/base/server/cms/src/com/netscape/cms/profile/def/CAEnrollDefault.java
index 14484e0..635c044 100644
--- a/base/server/cms/src/com/netscape/cms/profile/def/CAEnrollDefault.java
+++ b/base/server/cms/src/com/netscape/cms/profile/def/CAEnrollDefault.java
@@ -25,6 +25,7 @@ import java.security.cert.CertificateException;
 import com.netscape.certsrv.apps.CMS;
 import com.netscape.certsrv.base.EBaseException;
 import com.netscape.certsrv.ca.ICertificateAuthority;
+import com.netscape.cmsutil.crypto.CryptoUtil;
 
 import netscape.security.x509.CertificateX509Key;
 import netscape.security.x509.KeyIdentifier;
@@ -46,30 +47,29 @@ public abstract class CAEnrollDefault extends EnrollDefault {
     }
 
     public KeyIdentifier getKeyIdentifier(X509CertInfo info) {
+        String method = "CAEnrollDefault: getKeyIdentifier: ";
         try {
             CertificateX509Key ckey = (CertificateX509Key)
                     info.get(X509CertInfo.KEY);
             X509Key key = (X509Key) ckey.get(CertificateX509Key.KEY);
-            MessageDigest md = MessageDigest.getInstance("SHA-1");
-
-            md.update(key.getKey());
-            byte[] hash = md.digest();
+            byte[] hash = CryptoUtil.generateKeyIdentifier(key.getKey());
+            if (hash == null) {
+                CMS.debug(method +
+                    "CryptoUtil.generateKeyIdentifier returns null");
+                return null;
+            }
 
             return new KeyIdentifier(hash);
         } catch (IOException e) {
-            CMS.debug("AuthorityKeyIdentifierExtDefault: getKeyId " +
-                    e.toString());
+            CMS.debug(method + e.toString());
         } catch (CertificateException e) {
-            CMS.debug("AuthorityKeyIdentifierExtDefault: getKeyId " +
-                    e.toString());
-        } catch (NoSuchAlgorithmException e) {
-            CMS.debug("AuthorityKeyIdentifierExtDefault: getKeyId " +
-                    e.toString());
+            CMS.debug(method + e.toString());
         }
         return null;
     }
 
     public KeyIdentifier getCAKeyIdentifier(ICertificateAuthority ca) throws EBaseException {
+        String method = "CAEnrollDefault: getCAKeyIdentifier: ";
         X509CertImpl caCert = ca.getCACert();
         if (caCert == null) {
             // during configuration, we dont have the CA certificate
@@ -89,16 +89,11 @@ public abstract class CAEnrollDefault extends EnrollDefault {
             }
         }
 
-        try {
-            MessageDigest md = MessageDigest.getInstance("SHA-1");
-
-            md.update(key.getKey());
-            byte[] hash = md.digest();
-
-            return new KeyIdentifier(hash);
-        } catch (NoSuchAlgorithmException e) {
-            CMS.debug("AuthorityKeyIdentifierExtDefault: getKeyId " +
-                    e.toString());
+        byte[] hash = CryptoUtil.generateKeyIdentifier(key.getKey());
+        if (hash == null) {
+            CMS.debug(method +
+                "CryptoUtil.generateKeyIdentifier returns null");
+            return null;
         }
         return null;
     }
diff --git a/base/server/cms/src/com/netscape/cms/profile/def/SubjectKeyIdentifierExtDefault.java b/base/server/cms/src/com/netscape/cms/profile/def/SubjectKeyIdentifierExtDefault.java
index a8f6a74..d787575 100644
--- a/base/server/cms/src/com/netscape/cms/profile/def/SubjectKeyIdentifierExtDefault.java
+++ b/base/server/cms/src/com/netscape/cms/profile/def/SubjectKeyIdentifierExtDefault.java
@@ -37,6 +37,7 @@ import com.netscape.certsrv.property.Descriptor;
 import com.netscape.certsrv.property.EPropertyException;
 import com.netscape.certsrv.property.IDescriptor;
 import com.netscape.certsrv.request.IRequest;
+import com.netscape.cmsutil.crypto.CryptoUtil;
 
 /**
  * This class implements an enrollment default policy
@@ -195,22 +196,26 @@ public class SubjectKeyIdentifierExtDefault extends EnrollExtDefault {
     }
 
     public KeyIdentifier getKeyIdentifier(X509CertInfo info) {
+        String method = "SubjectKeyIdentifierExtDefault: getKeyIdentifier: ";
         try {
             CertificateX509Key infokey = (CertificateX509Key)
                     info.get(X509CertInfo.KEY);
             X509Key key = (X509Key) infokey.get(CertificateX509Key.KEY);
-            MessageDigest md = MessageDigest.getInstance("SHA-1");
 
-            md.update(key.getKey());
-            byte[] hash = md.digest();
+            // "SHA-1" is default for CryptoUtil.generateKeyIdentifier.
+            // you could specify different algorithm with the alg parameter
+            // like this:
+            //byte[] hash = CryptoUtil.generateKeyIdentifier(key.getKey(), "SHA-256");
+            byte[] hash = CryptoUtil.generateKeyIdentifier(key.getKey());
 
+            if (hash == null) {
+                CMS.debug(method +
+                    "CryptoUtil.generateKeyIdentifier returns null");
+                return null;
+            }
             return new KeyIdentifier(hash);
-        } catch (NoSuchAlgorithmException e) {
-            CMS.debug("SubjectKeyIdentifierExtDefault: getKeyIdentifier " +
-                    e.toString());
         } catch (Exception e) {
-            CMS.debug("SubjectKeyIdentifierExtDefault: getKeyIdentifier " +
-                    e.toString());
+            CMS.debug(method + e.toString());
         }
         return null;
     }
diff --git a/base/server/cms/src/com/netscape/cms/profile/input/EnrollInput.java b/base/server/cms/src/com/netscape/cms/profile/input/EnrollInput.java
index 84a6398..7665006 100644
--- a/base/server/cms/src/com/netscape/cms/profile/input/EnrollInput.java
+++ b/base/server/cms/src/com/netscape/cms/profile/input/EnrollInput.java
@@ -179,6 +179,7 @@ public abstract class EnrollInput implements IProfileInput {
 
     public void verifyPOP(Locale locale, CertReqMsg certReqMsg)
             throws EProfileException {
+        String method = "EnrollInput: verifyPOP: ";
         CMS.debug("EnrollInput ::in verifyPOP");
 
         String auditMessage = null;
@@ -217,7 +218,7 @@ public abstract class EnrollInput implements IProfileInput {
 
             // store a message in the signed audit log file
             auditMessage = CMS.getLogMessage(
-                    AuditEvent.PROOF_OF_POSSESSION,
+                    AuditEvent.PROOF_OF_POSSESSION_SUCCESS,
                     auditSubjectID,
                     ILogger.SUCCESS);
             audit(auditMessage);
@@ -228,9 +229,10 @@ public abstract class EnrollInput implements IProfileInput {
 
             // store a message in the signed audit log file
             auditMessage = CMS.getLogMessage(
-                    AuditEvent.PROOF_OF_POSSESSION,
+                    AuditEvent.PROOF_OF_POSSESSION_FAILURE,
                     auditSubjectID,
-                    ILogger.FAILURE);
+                    ILogger.FAILURE,
+                    method + e.toString());
 
             audit(auditMessage);
 
diff --git a/base/server/cms/src/com/netscape/cms/servlet/processors/CRMFProcessor.java b/base/server/cms/src/com/netscape/cms/servlet/processors/CRMFProcessor.java
index 70a4a42..58cdd3c 100644
--- a/base/server/cms/src/com/netscape/cms/servlet/processors/CRMFProcessor.java
+++ b/base/server/cms/src/com/netscape/cms/servlet/processors/CRMFProcessor.java
@@ -98,6 +98,7 @@ public class CRMFProcessor extends PKIProcessor {
      */
     private void verifyPOP(CertReqMsg certReqMsg)
             throws EBaseException {
+        String method = "CRMFProcessor: verifyPOP: ";
         String auditMessage = null;
         String auditSubjectID = auditSubjectID();
 
@@ -116,7 +117,7 @@ public class CRMFProcessor extends PKIProcessor {
 
                         // store a message in the signed audit log file
                         auditMessage = CMS.getLogMessage(
-                                AuditEvent.PROOF_OF_POSSESSION,
+                                AuditEvent.PROOF_OF_POSSESSION_SUCCESS,
                                 auditSubjectID,
                                 ILogger.SUCCESS);
 
@@ -129,9 +130,10 @@ public class CRMFProcessor extends PKIProcessor {
 
                         // store a message in the signed audit log file
                         auditMessage = CMS.getLogMessage(
-                                AuditEvent.PROOF_OF_POSSESSION,
+                                AuditEvent.PROOF_OF_POSSESSION_FAILURE,
                                 auditSubjectID,
-                                ILogger.FAILURE);
+                                ILogger.FAILURE,
+                                method + e.toString());
 
                         audit(auditMessage);
 
@@ -146,9 +148,10 @@ public class CRMFProcessor extends PKIProcessor {
 
                     // store a message in the signed audit log file
                     auditMessage = CMS.getLogMessage(
-                            AuditEvent.PROOF_OF_POSSESSION,
+                            AuditEvent.PROOF_OF_POSSESSION_FAILURE,
                             auditSubjectID,
-                            ILogger.FAILURE);
+                            ILogger.FAILURE,
+                            method + "required POP missing");
 
                     audit(auditMessage);
 
@@ -159,9 +162,10 @@ public class CRMFProcessor extends PKIProcessor {
         } catch (EBaseException eAudit1) {
             // store a message in the signed audit log file
             auditMessage = CMS.getLogMessage(
-                    AuditEvent.PROOF_OF_POSSESSION,
+                    AuditEvent.PROOF_OF_POSSESSION_FAILURE,
                     auditSubjectID,
-                    ILogger.FAILURE);
+                    ILogger.FAILURE,
+                    method + eAudit1.toString());
 
             audit(auditMessage);
         }
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 1e128d0..a1b01f4 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
@@ -39,12 +39,16 @@ import org.mozilla.jss.pkix.cmc.OtherInfo;
 import org.mozilla.jss.pkix.cmc.TaggedAttribute;
 
 import com.netscape.certsrv.apps.CMS;
+import com.netscape.certsrv.authentication.EInvalidCredentials;
+import com.netscape.certsrv.authentication.EMissingCredential;
 import com.netscape.certsrv.authentication.IAuthManager;
 import com.netscape.certsrv.authentication.IAuthToken;
 import com.netscape.certsrv.authorization.AuthzToken;
 import com.netscape.certsrv.base.EBaseException;
 import com.netscape.certsrv.base.SessionContext;
 import com.netscape.certsrv.logging.ILogger;
+import com.netscape.certsrv.logging.event.AuthFailEvent;
+import com.netscape.certsrv.logging.event.AuthSuccessEvent;
 import com.netscape.certsrv.logging.event.CertRequestProcessedEvent;
 import com.netscape.certsrv.profile.EDeferException;
 import com.netscape.certsrv.profile.EProfileException;
@@ -143,6 +147,7 @@ public class ProfileSubmitCMCServlet extends ProfileServlet {
 
     public IAuthToken authenticate(IProfileAuthenticator authenticator,
             HttpServletRequest request) throws EBaseException {
+        String method = "ProfileSubmitCMCServlet: authenticate: ";
         AuthCredentials credentials = new AuthCredentials();
 
         // build credential
@@ -158,15 +163,47 @@ public class ProfileSubmitCMCServlet extends ProfileServlet {
                     credentials.set(authName, request.getParameter(authName));
             }
         }
-        IAuthToken authToken = authenticator.authenticate(credentials);
 
+        IAuthToken authToken = null;
+        String auditSubjectID = null;
+        String authMgrID = authenticator.getName();
         SessionContext sc = SessionContext.getContext();
-        if (sc != null) {
-            sc.put(SessionContext.AUTH_MANAGER_ID, authenticator.getName());
-            String userid = authToken.getInString(IAuthToken.USER_ID);
-            if (userid != null) {
-                sc.put(SessionContext.USER_ID, userid);
+
+        try {
+            authToken = authenticator.authenticate(credentials);
+            if (sc != null) {
+                sc.put(SessionContext.AUTH_MANAGER_ID, authMgrID);
+                auditSubjectID = authToken.getInString(IAuthToken.USER_ID);
+                if (auditSubjectID != null) {
+                    CMS.debug(method + "setting auditSubjectID in SessionContext:" +
+                            auditSubjectID);
+                    sc.put(SessionContext.USER_ID, auditSubjectID);
+                } else {
+                    CMS.debug(method + "no auditSubjectID found in authToken");
+                }
+            }
+
+            if (!auditSubjectID.equals(ILogger.UNIDENTIFIED) &&
+                    !auditSubjectID.equals(ILogger.NONROLEUSER)) {
+                audit(new AuthSuccessEvent(
+                        auditSubjectID,
+                        ILogger.SUCCESS,
+                        authMgrID));
+            }
+
+        } catch (EBaseException e) {
+            CMS.debug(method + e);
+            String attempted_auditSubjectID = null;
+            if (sc != null) {
+                attempted_auditSubjectID =
+                        (String) sc.get(SessionContext.USER_ID);
             }
+            audit(new AuthFailEvent(
+                    auditSubjectID,
+                    ILogger.FAILURE,
+                    authMgrID,
+                    attempted_auditSubjectID));
+            throw(e);
         }
 
         return authToken;
diff --git a/base/server/cmsbundle/src/LogMessages.properties b/base/server/cmsbundle/src/LogMessages.properties
index d3ac06a..e280a55 100644
--- a/base/server/cmsbundle/src/LogMessages.properties
+++ b/base/server/cmsbundle/src/LogMessages.properties
@@ -2180,10 +2180,25 @@ LOGGING_SIGNED_AUDIT_AUTH_SUCCESS_3=<type=AUTH_SUCCESS>:[AuditEvent=AUTH_SUCCESS
 #
 LOGGING_SIGNED_AUDIT_CERT_PROFILE_APPROVAL_4=<type=CERT_PROFILE_APPROVAL>:[AuditEvent=CERT_PROFILE_APPROVAL][SubjectID={0}][Outcome={1}][ProfileID={2}][Op={3}] certificate approval
 #
-# LOGGING_SIGNED_AUDIT_PROOF_OF_POSSESSION
-# - used when proof of possession is checked during certificate enrollment
+# LOGGING_SIGNED_AUDIT_PROOF_OF_POSSESSION_SUCCESS
+# - used when proof of possession succeeded during certificate enrollment
 #
-LOGGING_SIGNED_AUDIT_PROOF_OF_POSSESSION_2=<type=PROOF_OF_POSSESSION>:[AuditEvent=PROOF_OF_POSSESSION][SubjectID={0}][Outcome={1}] checking proof of possession
+LOGGING_SIGNED_AUDIT_PROOF_OF_POSSESSION_SUCCESS_2=<type=PROOF_OF_POSSESSION_SUCCESS>:[AuditEvent=PROOF_OF_POSSESSION][SubjectID={0}][Outcome={1}] proof of possession succeeded
+#
+# LOGGING_SIGNED_AUDIT_PROOF_OF_POSSESSION_FAILURE
+# - used when proof of possession failed during certificate enrollment
+#
+LOGGING_SIGNED_AUDIT_PROOF_OF_POSSESSION_FAILURE_3=<type=PROOF_OF_POSSESSION_FAILURE>:[AuditEvent=PROOF_OF_POSSESSION_FAILURE][SubjectID={0}][Outcome={1}][Info={2}] proof of possession failed
+#
+# LOGGING_SIGNED_AUDIT_CMC_PROOF_OF_IDENTIFICATION_SUCCESS
+# - used when proof of identification succeeded during CMC request processing
+#
+LOGGING_SIGNED_AUDIT_CMC_PROOF_OF_IDENTIFICATION_SUCCESS_2=<type=CMC_PROOF_OF_IDENTIFICATION_SUCCESS>:[AuditEvent=CMC_PROOF_OF_IDENTIFICATION_SUCCESS][AttemptedCred={0}][Outcome={1}] failed proof of identification in CMC request
+#
+# LOGGING_SIGNED_AUDIT_CMC_PROOF_OF_IDENTIFICATION_FAILURE
+# - used when proof of identification failed during CMC request processing
+#
+LOGGING_SIGNED_AUDIT_CMC_PROOF_OF_IDENTIFICATION_FAILURE_3=<type=CMC_PROOF_OF_IDENTIFICATION_FAILURE>:[AuditEvent=CMC_PROOF_OF_IDENTIFICATION_FAILURE][AttemptedCred={0}][Outcome={1}][Info={2}] failed proof of identification in CMC request
 #
 # LOGGING_SIGNED_AUDIT_CRL_RETRIEVAL
 # - used when CRLs are retrieved by the OCSP Responder
@@ -2235,7 +2250,16 @@ LOGGING_SIGNED_AUDIT_OCSP_REMOVE_CA_REQUEST_PROCESSED_FAILURE_3=<type=OCSP_REMOV
 # SignerInfo must be a unique String representation for the signer
 #
 LOGGING_SIGNED_AUDIT_CMC_SIGNED_REQUEST_SIG_VERIFY_5=<type=CMC_SIGNED_REQUEST_SIG_VERIFY>:[AuditEvent=CMC_SIGNED_REQUEST_SIG_VERIFY][SubjectID={0}][Outcome={1}][ReqType={2}][CertSubject={3}][SignerInfo={4}] agent pre-approved CMC request signature verification
-LOGGING_SIGNED_AUDIT_CMC_USER_SIGNED_REQUEST_SIG_VERIFY_5=<type=CMC_USER_SIGNED_REQUEST_SIG_VERIFY>:[AuditEvent=CMC_USER_SIGNED_REQUEST_SIG_VERIFY][SubjectID={0}][Outcome={1}][ReqType={2}][CertSubject={3}][SignerInfo={4}] User signed CMC request signature verification
+#
+# LOGGING_SIGNED_AUDIT_CMC_USER_SIGNED_REQUEST_SIG_VERIFY
+# - used when CMC (user-signed or self-signed) certificate requests or revocation requests
+#   are submitted and signature is verified
+# ReqType must be the request type (enrollment, or revocation)
+# CertSubject must be the certificate subject name of the certificate request
+# SignerInfo must be a unique String representation for the signer
+#
+LOGGING_SIGNED_AUDIT_CMC_USER_SIGNED_REQUEST_SIG_VERIFY_SUCCESS_5=<type=CMC_USER_SIGNED_REQUEST_SIG_VERIFY_SUCCESS>:[AuditEvent=CMC_USER_SIGNED_REQUEST_SIG_VERIFY_SUCCESS][SubjectID={0}][Outcome={1}][ReqType={2}][CertSubject={3}][SignerInfo={4}] User signed CMC request signature verification success
+LOGGING_SIGNED_AUDIT_CMC_USER_SIGNED_REQUEST_SIG_VERIFY_FAILURE_6=<type=CMC_USER_SIGNED_REQUEST_SIG_VERIFY_FAILURE>:[AuditEvent=CMC_USER_SIGNED_REQUEST_SIG_VERIFY_FAILURE][SubjectID={0}][Outcome={1}][ReqType={2}][CertSubject={3}][SignerInfo={4}][info={5}] User signed CMC request signature verification failure
 
 # LOGGING_SIGNED_AUDIT_COMPUTE_RANDOM_DATA_REQUEST 
 # - used for TPS to TKS to get random challenge data
diff --git a/base/server/cmscore/src/com/netscape/cmscore/security/KeyCertUtil.java b/base/server/cmscore/src/com/netscape/cmscore/security/KeyCertUtil.java
index 6dabd0c..177d540 100644
--- a/base/server/cmscore/src/com/netscape/cmscore/security/KeyCertUtil.java
+++ b/base/server/cmscore/src/com/netscape/cmscore/security/KeyCertUtil.java
@@ -1032,13 +1032,17 @@ public class KeyCertUtil {
 
     public static KeyIdentifier createKeyIdentifier(KeyPair keypair)
             throws NoSuchAlgorithmException, InvalidKeyException {
-        MessageDigest md = MessageDigest.getInstance("SHA-1");
         X509Key subjectKeyInfo = convertPublicKeyToX509Key(
                 keypair.getPublic());
 
-        //md.update(subjectKeyInfo.getEncoded());
-        md.update(subjectKeyInfo.getKey());
-        return new KeyIdentifier(md.digest());
+        byte[] hash = CryptoUtil.generateKeyIdentifier(subjectKeyInfo.getKey());
+
+        if (hash == null) {
+            CMS.debug("KeyCertUtil: createKeyIdentifier " +
+                "CryptoUtil.generateKeyIdentifier returns null");
+            return null;
+        }
+        return new KeyIdentifier(hash);
     }
 
     public static BigInteger getSerialNumber(LDAPConnection conn, String baseDN)
diff --git a/base/util/src/com/netscape/cmsutil/crypto/CryptoUtil.java b/base/util/src/com/netscape/cmsutil/crypto/CryptoUtil.java
index d22856d..b768142 100644
--- a/base/util/src/com/netscape/cmsutil/crypto/CryptoUtil.java
+++ b/base/util/src/com/netscape/cmsutil/crypto/CryptoUtil.java
@@ -27,6 +27,7 @@ import java.net.SocketException;
 import java.security.InvalidAlgorithmParameterException;
 import java.security.InvalidKeyException;
 import java.security.KeyPair;
+import java.security.MessageDigest;
 import java.security.NoSuchAlgorithmException;
 import java.security.NoSuchProviderException;
 import java.security.PublicKey;
@@ -127,6 +128,7 @@ import netscape.security.util.DerValue;
 import netscape.security.util.ObjectIdentifier;
 import netscape.security.util.WrappingParams;
 import netscape.security.x509.AlgorithmId;
+import netscape.security.x509.CertAttrSet;
 import netscape.security.x509.CertificateAlgorithmId;
 import netscape.security.x509.CertificateChain;
 import netscape.security.x509.CertificateExtensions;
@@ -136,7 +138,11 @@ import netscape.security.x509.CertificateSubjectName;
 import netscape.security.x509.CertificateValidity;
 import netscape.security.x509.CertificateVersion;
 import netscape.security.x509.CertificateX509Key;
+import netscape.security.x509.Extension;
 import netscape.security.x509.Extensions;
+import netscape.security.x509.KeyIdentifier;
+import netscape.security.x509.PKIXExtensions;
+import netscape.security.x509.SubjectKeyIdentifierExtension;
 import netscape.security.x509.X500Name;
 import netscape.security.x509.X500Signer;
 import netscape.security.x509.X509CertImpl;
@@ -1536,10 +1542,33 @@ public class CryptoUtil {
      * This createCertificationRequest() allows extensions to be added to the CSR
      */
     public static PKCS10 createCertificationRequest(String subjectName,
+            KeyPair keyPair, Extensions exts)
+            throws NoSuchAlgorithmException, NoSuchProviderException,
+            InvalidKeyException, IOException, CertificateException,
+            SignatureException {
+        String method = "CryptoUtil: createCertificationRequest: ";
+
+        String alg = "SHA256withRSA";
+        PublicKey pubk = keyPair.getPublic();
+        X509Key key = convertPublicKeyToX509Key(pubk);
+        if (pubk instanceof RSAPublicKey) {
+            alg = "SHA256withRSA";
+        } else if (isECCKey(key)) {
+            alg = "SHA256withEC";
+        } else {
+            throw new NoSuchAlgorithmException(method + alg);
+        }
+
+        return createCertificationRequest(
+                subjectName, key, (org.mozilla.jss.crypto.PrivateKey) keyPair.getPrivate(),
+                alg, exts);
+    }
+
+    public static PKCS10 createCertificationRequest(String subjectName,
             X509Key pubk, PrivateKey prik, String alg, Extensions exts)
             throws NoSuchAlgorithmException, NoSuchProviderException,
-                InvalidKeyException, IOException, CertificateException,
-                SignatureException {
+            InvalidKeyException, IOException, CertificateException,
+            SignatureException {
         X509Key key = pubk;
         java.security.Signature sig = java.security.Signature.getInstance(alg,
                 "Mozilla-JSS");
@@ -1548,11 +1577,12 @@ public class CryptoUtil {
         PKCS10 pkcs10 = null;
 
         if (exts != null && !exts.isEmpty()) {
-            PKCS10Attribute attr = new
-                    PKCS10Attribute(PKCS9Attribute.EXTENSION_REQUEST_OID,
-                            exts);
+            PKCS10Attribute attr = new PKCS10Attribute(PKCS9Attribute.EXTENSION_REQUEST_OID,
+                    exts);
             PKCS10Attributes attrs = new PKCS10Attributes();
 
+            System.out.println("PKCS10: createCertificationRequest: adding attribute name =" +
+                    attr.getAttributeValue().getName());
             attrs.setAttribute(attr.getAttributeValue().getName(), attr);
 
             pkcs10 = new PKCS10(key, attrs);
@@ -1566,6 +1596,51 @@ public class CryptoUtil {
         return pkcs10;
     }
 
+    public static KeyIdentifier createKeyIdentifier(KeyPair keypair)
+            throws NoSuchAlgorithmException, InvalidKeyException {
+        String method = "CryptoUtil: createKeyIdentifier: ";
+        System.out.println(method + "begins");
+
+        X509Key subjectKeyInfo = convertPublicKeyToX509Key(
+                keypair.getPublic());
+
+        byte[] hash = generateKeyIdentifier(subjectKeyInfo.getKey());
+
+        if (hash == null) {
+            System.out.println(method +
+                    "generateKeyIdentifier returns null");
+            return null;
+        }
+        return new KeyIdentifier(hash);
+    }
+
+    public static byte[] generateKeyIdentifier(byte[] rawKey) {
+        return generateKeyIdentifier(rawKey, null);
+    }
+
+    public static byte[] generateKeyIdentifier(byte[] rawKey, String alg) {
+        String method = "CryptoUtil: generateKeyIdentifier: ";
+        String msg = "";
+        if (alg == null) {
+            alg = "SHA-1";
+        }
+        try {
+            MessageDigest md = MessageDigest.getInstance(alg);
+
+            md.update(rawKey);
+            byte[] hash = md.digest();
+
+            return hash;
+        } catch (NoSuchAlgorithmException e) {
+            msg = method + e;
+            System.out.println(msg);
+        } catch (Exception e) {
+            msg = method + e;
+            System.out.println(msg);
+        }
+        return null;
+    }
+
     /**
      * Creates a PKCS#10 request.
      */
@@ -1611,6 +1686,102 @@ public class CryptoUtil {
         return pkcs10;
     }
 
+    /*
+     * get extention from  PKCS10 request
+     */
+    public static netscape.security.x509.Extension getExtensionFromPKCS10(PKCS10 pkcs10, String extnName)
+            throws IOException, CertificateException {
+        Extension extn = null;
+
+        String method = "CryptoUtiil: getExtensionFromPKCS10: ";
+        System.out.println(method + "begins");
+
+        PKCS10Attributes attributeSet = pkcs10.getAttributes();
+        if (attributeSet == null) {
+            System.out.println(method + "attributeSet not found");
+            return null;
+        }
+        PKCS10Attribute attr = attributeSet.getAttribute("extensions");
+        if (attr == null) {
+            System.out.println(method + "extensions attribute not found");
+            return null;
+        }
+        System.out.println(method + attr.toString());
+
+        CertAttrSet cas = attr.getAttributeValue();
+        if (cas == null) {
+            System.out.println(method + "CertAttrSet not found in PKCS10Attribute");
+            return null;
+        }
+
+        Enumeration<String> en = cas.getAttributeNames();
+        while (en.hasMoreElements()) {
+            String name = en.nextElement();
+            System.out.println(method + " checking extension in request:" + name);
+            if (name.equals(extnName)) {
+                System.out.println(method + "extension matches");
+                extn = (Extension)cas.get(name);
+            }
+        }
+
+        System.out.println(method + "ends");
+        return extn;
+    }
+
+    /*
+     * get extension from CRMF cert request (CertTemplate)
+     */
+    public static netscape.security.x509.Extension getExtensionFromCertTemplate(CertTemplate certTemplate, ObjectIdentifier csOID) {
+        //ObjectIdentifier csOID = PKIXExtensions.SubjectKey_Id;
+        OBJECT_IDENTIFIER jssOID =
+                new OBJECT_IDENTIFIER(csOID.toString());
+/*
+        return getExtensionFromCertTemplate(certTemplate, jssOID);
+    }
+    public static netscape.security.x509.Extension getExtensionFromCertTemplate(CertTemplate certTemplate, org.mozilla.jss.asn1.OBJECT_IDENTIFIER jssOID) {
+*/
+
+        String method = "CryptoUtil: getSKIExtensionFromCertTemplate: ";
+        Extension extn = null;
+
+       /*
+        * there seems to be an issue with constructor in Extension
+        * when feeding SubjectKeyIdentifierExtension;
+        * Special-case it
+        */
+        OBJECT_IDENTIFIER SKIoid =
+                new OBJECT_IDENTIFIER(PKIXExtensions.SubjectKey_Id.toString());
+
+        if (certTemplate.hasExtensions()) {
+            int numexts = certTemplate.numExtensions();
+            for (int j = 0; j < numexts; j++) {
+                 org.mozilla.jss.pkix.cert.Extension jssext =
+                         certTemplate.extensionAt(j);
+                 org.mozilla.jss.asn1.OBJECT_IDENTIFIER extnoid =
+                         jssext.getExtnId();
+                 System.out.println(method + "checking extension in request:" + extnoid.toString());
+                 if (extnoid.equals(jssOID)) {
+                     System.out.println(method + "extension found");
+                     try {
+                       if (jssOID.equals(SKIoid)) {
+                         extn =
+                             new SubjectKeyIdentifierExtension(false, jssext.getExtnValue().toByteArray());
+                       } else {
+                         extn =
+                             new netscape.security.x509.Extension(csOID, false, jssext.getExtnValue().toByteArray());
+                       }
+                     } catch (IOException e) {
+                       System.out.println(method + e);
+                     }
+                 }
+            }
+        } else {
+            System.out.println(method + "no extension found");
+        }
+
+        return extn;
+    }
+
     public static void unTrustCert(InternalCertificate cert) {
         // remove TRUSTED_CA
         int flag = cert.getSSLTrust();
diff --git a/base/util/src/netscape/security/pkcs/PKCS10.java b/base/util/src/netscape/security/pkcs/PKCS10.java
index 0702e82..10933b0 100644
--- a/base/util/src/netscape/security/pkcs/PKCS10.java
+++ b/base/util/src/netscape/security/pkcs/PKCS10.java
@@ -123,6 +123,13 @@ public class PKCS10 {
         byte sigData[];
         Signature sig;
 
+        String method = "PKCS10: PKCS10: ";
+        String msg = "";
+
+        System.out.println(method + "begins");
+        if (data == null) {
+            throw new IllegalArgumentException(method + "param data cann't be null");
+        }
         certificateRequest = data;
 
         //
@@ -131,9 +138,12 @@ public class PKCS10 {
         //
         in = new DerInputStream(data);
         seq = in.getSequence(3);
+        if (seq == null) {
+            throw new IllegalArgumentException(method + "in.getSequence null");
+        }
 
         if (seq.length != 3)
-            throw new IllegalArgumentException("not a PKCS #10 request");
+            throw new IllegalArgumentException(method + "not a PKCS #10 request");
 
         data = seq[0].toByteArray(); // reusing this variable
         certRequestInfo = seq[0].toByteArray(); // make a copy
@@ -152,20 +162,22 @@ public class PKCS10 {
         */
 
         subject = new X500Name(seq[0].data);
+        msg = "Request Subject: " + subject + ": ";
 
         byte val1[] = seq[0].data.getDerValue().toByteArray();
         subjectPublicKeyInfo = X509Key.parse(new DerValue(val1));
         PublicKey publicKey = X509Key.parsePublicKey(new DerValue(val1));
         if (publicKey == null) {
-            System.out.println("PKCS10: publicKey null");
-            throw new SignatureException ("publicKey null");
+            System.out.println(method + msg + "publicKey null");
+            throw new SignatureException (method + msg + "publicKey null");
         }
 
         // Cope with a somewhat common illegal PKCS #10 format
-        if (seq[0].data.available() != 0)
+        if (seq[0].data.available() != 0) {
             attributeSet = new PKCS10Attributes(seq[0].data);
-        else
+        } else {
             attributeSet = new PKCS10Attributes();
+        }
 
         //
         // OK, we parsed it all ... validate the signature using the
@@ -202,14 +214,15 @@ public class PKCS10 {
                 sig.initVerify(publicKey);
                 sig.update(data);
                 if (!sig.verify(sigData)) {
-                System.out.println("PKCS10: sig.verify() failed");
-                    throw new SignatureException("Invalid PKCS #10 signature");
+                    System.out.println(method + msg + "sig.verify() failed");
+                        throw new SignatureException(method + msg + "Invalid PKCS #10 signature");
                 }
             }
         } catch (InvalidKeyException e) {
-            System.out.println("PKCS10: "+ e.toString());
-            throw new SignatureException("invalid key");
+            System.out.println(method + msg + e.toString());
+            throw new SignatureException(method + msg + "invalid key");
         }
+        System.out.println(method + "ends");
     }
 
     public PKCS10(byte data[])
diff --git a/base/util/src/netscape/security/pkcs/PKCS10Attributes.java b/base/util/src/netscape/security/pkcs/PKCS10Attributes.java
index 4c97218..45d5695 100644
--- a/base/util/src/netscape/security/pkcs/PKCS10Attributes.java
+++ b/base/util/src/netscape/security/pkcs/PKCS10Attributes.java
@@ -66,6 +66,8 @@ public class PKCS10Attributes extends Vector<PKCS10Attribute> implements DerEnco
             for (int i = 0; i < attrs.length; i++) {
                 PKCS10Attribute attr = new PKCS10Attribute(attrs[i]);
                 addElement(attr);
+                System.out.println("PKCS10Attributes: adding attribute: " +
+                        attr.getAttributeValue().getName());
                 map.put(attr.getAttributeValue().getName(), attr);
             }
         }
-- 
2.7.4

