Skip to content

Commit

Permalink
Bug 2246422 ServerSideKeygen static SKID
Browse files Browse the repository at this point in the history
This patch intends to address the bug where in the case of
ServerSide keygen, a static SKI extension was injected as
a result.

fixes https://bugzilla.redhat.com/show_bug.cgi?id=2246422
  • Loading branch information
Christina Fu committed Nov 1, 2023
1 parent 48c41a8 commit 6081596
Show file tree
Hide file tree
Showing 3 changed files with 167 additions and 4 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,14 @@
import org.dogtagpki.server.ca.ICertificateAuthority;
import org.mozilla.jss.netscape.security.x509.CertificateSubjectName;
import org.mozilla.jss.netscape.security.x509.CertificateX509Key;
import org.mozilla.jss.netscape.security.x509.Extension;
import org.mozilla.jss.netscape.security.x509.KeyIdentifier;
import org.mozilla.jss.netscape.security.x509.PKIXExtensions;
import org.mozilla.jss.netscape.security.x509.SubjectKeyIdentifierExtension;
import org.mozilla.jss.netscape.security.x509.X500Name;
import org.mozilla.jss.netscape.security.x509.X509CertImpl;
import org.mozilla.jss.netscape.security.x509.X509CertInfo;
import org.mozilla.jss.netscape.security.x509.X509Key;
import org.mozilla.jss.pkix.crmf.PKIArchiveOptions;

import com.netscape.ca.CertificateAuthority;
Expand Down Expand Up @@ -292,31 +297,68 @@ public void execute(IRequest request)

// process certificate issuance
X509CertInfo info = request.getExtDataInCertInfo(REQUEST_CERTINFO);
logger.debug(method + "cfu before: X509CertInfo info = " + info.toString());

if (isSSKeygen) {
try {
String pubKeyStr = request.getExtDataInString("public_key");
if (pubKeyStr == null) {
throw new EProfileException("Server-Side Keygen enrollment failed to retrieve public_key from KRA");
}
//logger.debug(method + "pubKeyStr = " + pubKeyStr);
logger.debug(method + "pubKeyStr = " + pubKeyStr);
byte[] pubKeyB = CryptoUtil.base64Decode(pubKeyStr);
CertificateX509Key certKey = new CertificateX509Key(
new ByteArrayInputStream(pubKeyB));
Object oj = info.get(X509CertInfo.KEY);
if (oj != null) {

// replace fake key in info
CertificateX509Key infokey = (CertificateX509Key)
info.get(X509CertInfo.KEY);
if (infokey != null) {
X509Key key = (X509Key)
infokey.get(CertificateX509Key.KEY);
logger.debug(method + "key = " + key.toString());
// a placeholder temporary fake key was put in
// ServerKeygenUserKeyDefault
info.delete(X509CertInfo.KEY);
//logger.debug(method + " fake key deleted");
logger.debug(method + "key deleted");
}

// adding real key
info.set(X509CertInfo.KEY, certKey);

// fake key relaced;
// need to compute/replace SKI as well if present

Extension ext = CertUtils.getExtension(PKIXExtensions.SubjectKey_Id.toString(), info);
if (ext != null) {
logger.debug(method + "found SubjectKey_Id extension");
// compute keyId
X509Key realkey = (X509Key)
certKey.get(CertificateX509Key.KEY);
byte[] hash = CryptoUtil.generateKeyIdentifier(realkey.getKey());
KeyIdentifier id = new KeyIdentifier(hash);
SubjectKeyIdentifierExtension skiExt =
new SubjectKeyIdentifierExtension(id.getIdentifier());

// replace it
CertUtils.replaceExtension(PKIXExtensions.SubjectKey_Id.toString(), skiExt, info);
logger.debug(method + " SubjectKey_Id replaced");

logger.debug(method + " after replacement: X509CertInfo info = " + info.toString());
}/* else
Not every cert needs an SKI
logger.debug(method + "did not find SubjectKey_Id");
*/

} catch (IOException e) {
logger.debug(method + e);
throw new EProfileException(e);
} catch (CertificateException e) {
logger.debug(method + e);
throw new EProfileException(e);
} catch (Exception e) {
logger.debug(method + e);
throw new EProfileException(e);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -491,6 +491,7 @@ else if (keyType.contentEquals("EC")) {
request.setExtData(IRequest.SERVER_SIDE_KEYGEN_ENROLL_ENABLE_ARCHIVAL, enableArchival? "true":"false");

info.set(X509CertInfo.KEY, certKey);
logger.debug(method + "fake key injected for SSK.");
} catch (Exception e) {
logger.debug("ServerKeygenUserKeyDefault: populate " + e.toString());
throw new EProfileException(e.getMessage());
Expand Down
120 changes: 120 additions & 0 deletions base/server/src/main/java/com/netscape/cmscore/cert/CertUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@
import java.security.cert.X509CRL;
import java.security.cert.X509Certificate;
import java.util.Arrays;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.Locale;
Expand Down Expand Up @@ -569,6 +571,124 @@ public static String getCertType(X509CertImpl cert) throws CertificateParsingExc
return (sb.length() > 0) ? sb.toString() : null;
}

public static void addExtension(String name, Extension ext, X509CertInfo info)
throws EProfileException {
if (ext == null) {
throw new EProfileException("addExtension: extension '" + name + "' is null");
}
CertificateExtensions exts = null;

Extension alreadyPresentExtension = getExtension(name, info);

if (alreadyPresentExtension != null) {
String eName = ext.toString();
logger.error("Duplicate extension: " + eName);
throw new EProfileException(CMS.getUserMessage("CMS_PROFILE_DUPLICATE_EXTENSION", eName));
}

try {
exts = (CertificateExtensions)
info.get(X509CertInfo.EXTENSIONS);
} catch (Exception e) {
logger.warn("EnrollDefault: " + e.getMessage(), e);
}
if (exts == null) {
throw new EProfileException("extensions not found");
}
try {
exts.set(name, ext);
} catch (IOException e) {
logger.warn("EnrollDefault: " + e.getMessage(), e);
}
}

public static void deleteExtension(String extID, X509CertInfo info) throws Exception {

CertificateExtensions exts = (CertificateExtensions) info.get(X509CertInfo.EXTENSIONS);

if (exts == null) {
return;
}

Collection<String> names = new ArrayList<>();
Enumeration<String> e = exts.getNames();

// get names of extensions to remove
while (e.hasMoreElements()) {
String name = e.nextElement();
Extension ext = (Extension) exts.get(name);

if (ext.getExtensionId().toString().equals(extID)) {
names.add(name);
}
}

// remove extensions in separate loop to avoid ConcurrentModificationException
for (String name : names) {
exts.delete(name);
}
}

public static void replaceExtension(String name, Extension ext, X509CertInfo info)
throws EProfileException {
try {
deleteExtension(name, info);
} catch (Exception e) {
throw new EProfileException(e);
}

addExtension(name, ext, info);
}

public static Extension getExtension(String name, X509CertInfo info) {

if (info == null) {
logger.error("Missing certificate info");
return null;
}

CertificateExtensions exts = null;

try {
exts = (CertificateExtensions) info.get(X509CertInfo.EXTENSIONS);
} catch (Exception e) {
logger.warn("EnrollDefault: getExtension " + e.getMessage(), e);
}

if (exts == null) {
logger.debug("EnrollDefault: Unable to find extensions");
return null;
}

return getExtension(name, exts);
}

public static Extension getExtension(String name, CertificateExtensions exts) {

logger.debug("EnrollDefault: Searching for " + name + " extension");

if (exts == null) {
logger.error("Missing certificate extensions");
return null;
}

Enumeration<Extension> e = exts.getAttributes();

logger.debug("EnrollDefault: Extensions:");
while (e.hasMoreElements()) {
Extension ext = e.nextElement();
logger.debug("EnrollDefault: - " + ext.getExtensionId());

if (ext.getExtensionId().toString().equals(name)) {
logger.debug("EnrollDefault: Found extension " + name);
return ext;
}
}

logger.debug("EnrollDefault: Extension " + name + " not found");
return null;
}

public static String getNSExtensionInfo(NSCertTypeExtension nsExtn) {
StringBuffer sb = new StringBuffer();

Expand Down

0 comments on commit 6081596

Please sign in to comment.