Skip to content

Commit

Permalink
Merge branch 'main' into resource-test
Browse files Browse the repository at this point in the history
  • Loading branch information
edewit authored Oct 6, 2023
2 parents e62990a + 0853d48 commit ef203b7
Show file tree
Hide file tree
Showing 66 changed files with 940 additions and 1,637 deletions.
2 changes: 2 additions & 0 deletions .github/actions/upload-heapdumps/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ runs:
steps:
- id: upload-jvm-heapdumps
name: Upload JVM Heapdumps
# Windows runners are running into https://github.com/actions/upload-artifact/issues/240
if: runner.os != 'Windows'
uses: actions/upload-artifact@v3
with:
name: jvm-heap-dumps
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@

import javax.security.auth.x500.X500Principal;

import org.jboss.logging.Logger;
import org.keycloak.common.crypto.CertificateUtilsProvider;
import org.wildfly.security.asn1.ASN1;
import org.wildfly.security.asn1.DERDecoder;
Expand All @@ -60,6 +61,8 @@
*/
public class ElytronCertificateUtils implements CertificateUtilsProvider {

Logger log = Logger.getLogger(getClass());

/**
* Generates version 3 {@link java.security.cert.X509Certificate}.
*
Expand Down Expand Up @@ -249,16 +252,29 @@ public List<String> getCRLDistributionPoints(X509Certificate cert) throws IOExce
case ASN1.UTF8_STRING_TYPE:
distPointUrls.add(der.decodeUtf8String());
break;
case 0xa0:
der.decodeImplicit(0xa0);
byte[] edata = der.decodeOctetString();
while(!Character.isLetterOrDigit(edata[0])) {
edata = Arrays.copyOfRange(edata, 1, edata.length);
}
distPointUrls.add(new String(edata));
case 0xa0: // Decode CRLDistributionPoint FullName list
der.startExplicit(0xa0);
break;
case 0x86: // Decode CRLDistributionPoint FullName
der.decodeImplicit(0x86);
distPointUrls.add(der.decodeOctetStringAsString());
log.debug("Adding Dist point name: " + distPointUrls.get(distPointUrls.size()-1));
break;
default:
der.skipElement();
}
// Check to see if there is another sequence to process
try {
if(!der.hasNextElement() && der.peekType() == ASN1.SEQUENCE_TYPE) {
der.startSequence();
} else if (!der.hasNextElement() && der.peekType() == 0xa0) {
der.startExplicit(0xa0);
}

} catch(Exception e) {
// Just log this error. Likely the Dist points have been parsed, but
// the end of the cert is failing to parse.
log.warn("There is an issue parsing the certificate for Distribution Points", e);

}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
import java.io.IOException;
import java.math.BigInteger;

import org.jboss.logging.Logger;
import org.keycloak.common.crypto.ECDSACryptoProvider;
import org.wildfly.security.asn1.DERDecoder;
import org.wildfly.security.asn1.DEREncoder;
Expand All @@ -28,6 +29,8 @@
*/
public class ElytronECDSACryptoProvider implements ECDSACryptoProvider {

Logger log = Logger.getLogger(getClass());

@Override
public byte[] concatenatedRSToASN1DER(final byte[] signature, int signLength) throws IOException {
int len = signLength / 2;
Expand All @@ -45,6 +48,7 @@ public byte[] concatenatedRSToASN1DER(final byte[] signature, int signLength) th
seq.startSequence();
seq.encodeInteger(rBigInteger);
seq.encodeInteger(sBigInteger);
seq.endSequence();

return seq.getEncoded();

Expand All @@ -56,13 +60,35 @@ public byte[] asn1derToConcatenatedRS(final byte[] derEncodedSignatureValue, int

DERDecoder der = new DERDecoder(derEncodedSignatureValue);
der.startSequence();
byte[] r = der.decodeInteger().toByteArray();
byte[] s = der.decodeInteger().toByteArray();
byte[] r = convertToBytes(der.decodeInteger(),len);
byte[] s = convertToBytes(der.decodeInteger(),len);
der.endSequence();
byte[] concatenatedSignatureValue = new byte[signLength];

System.arraycopy(r, 0, concatenatedSignatureValue, 0, len);
System.arraycopy(s, 0, concatenatedSignatureValue, len, len);

return concatenatedSignatureValue;
}

// If byte array length doesn't match expected length, copy to new
// byte array of the expected length
private byte[] convertToBytes(BigInteger decodeInteger, int len) {

byte[] bytes = decodeInteger.toByteArray();

if(len < bytes.length) {
log.debug("Decoded integer byte length greater than expected.");
byte[] t = new byte[len];
System.arraycopy(bytes, bytes.length - len, t, 0, len);
bytes = t;
} else if (len > bytes.length) {
log.debug("Decoded integer byte length less than expected.");
byte[] t = new byte[len];
System.arraycopy(bytes, 0, t, len - bytes.length, bytes.length);
bytes = t;
}
return bytes;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -16,24 +16,42 @@
*/
package org.keycloak.crypto.elytron;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.security.InvalidAlgorithmParameterException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.CRLReason;
import java.security.cert.CertPath;
import java.security.cert.CertPathBuilder;
import java.security.cert.CertPathBuilderException;
import java.security.cert.CertPathValidator;
import java.security.cert.CertPathValidatorException;
import java.security.cert.CertPathValidatorResult;
import java.security.cert.Certificate;
import java.security.cert.CertificateEncodingException;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.cert.PKIXBuilderParameters;
import java.security.cert.PKIXCertPathValidatorResult;
import java.security.cert.PKIXParameters;
import java.security.cert.PKIXRevocationChecker;
import java.security.cert.X509CertSelector;
import java.security.cert.X509Certificate;
import java.util.Arrays;
import java.util.Date;
import java.util.EnumSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

import javax.net.ssl.TrustManagerFactory;

import org.jboss.logging.Logger;
import org.keycloak.common.util.PemUtils;
import org.keycloak.models.KeycloakSession;
import org.keycloak.utils.OCSPProvider;
import org.wildfly.security.asn1.ASN1;
Expand Down Expand Up @@ -61,31 +79,46 @@ public class ElytronOCSPProvider extends OCSPProvider {
* @throws CertPathValidatorException
*/
@Override
protected OCSPRevocationStatus check(KeycloakSession session, X509Certificate cert, X509Certificate issuerCertificate, List<URI> responderURIs, X509Certificate responderCert, Date date) throws CertPathValidatorException {
protected OCSPRevocationStatus check(KeycloakSession session, X509Certificate cert,
X509Certificate issuerCertificate, List<URI> responderURIs, X509Certificate responderCert, Date date)
throws CertPathValidatorException {
if (responderURIs == null || responderURIs.size() == 0)
throw new IllegalArgumentException("Need at least one responder");

try {
try {
KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType());
trustStore.load(null,"pass".toCharArray());
trustStore.setCertificateEntry("trust", cert);
TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());


X509RevocationTrustManager trustMgr = X509RevocationTrustManager.builder()
.setOcspResponderCert(responderCert)
.setTrustStore(trustStore)
.setTrustManagerFactory(trustManagerFactory)
.build()
;

X509Certificate[] certs = { cert };
trustMgr.checkClientTrusted(certs, cert.getType());
} catch (NoSuchAlgorithmException | CertificateException | IOException | KeyStoreException e) {
trustStore.load(null, "pass".toCharArray());
trustStore.setCertificateEntry("trust", issuerCertificate);

CertPathBuilder cpb = CertPathBuilder.getInstance("PKIX");
CertificateFactory cf = CertificateFactory.getInstance("X.509");
CertPathValidator cpv = CertPathValidator.getInstance("PKIX");
PKIXRevocationChecker rc = (PKIXRevocationChecker) cpb.getRevocationChecker();
X509CertSelector certSelector = new X509CertSelector();

X509Certificate[] certs = { cert };
certSelector.setCertificate(cert);
certSelector.setCertificateValid(date);

CertPath cp = cf.generateCertPath(Arrays.asList(certs));

PKIXParameters params = new PKIXBuilderParameters(trustStore, certSelector);

rc.setOcspResponder(responderURIs.get(0));
rc.setOcspResponderCert(responderCert);
rc.setOptions(EnumSet.noneOf(PKIXRevocationChecker.Option.class));
params.setRevocationEnabled(false);
params.addCertPathChecker(rc);

PKIXCertPathValidatorResult result = (PKIXCertPathValidatorResult) cpv.validate(cp, params);
logger.debug("Certificate validated by CA: " + result.getTrustAnchor().getCAName());

} catch (InvalidAlgorithmParameterException | NoSuchAlgorithmException | CertificateException | IOException
| KeyStoreException e) {
logger.warn("OSCP Response check failed.", e);
return unknownStatus();
}

return new OCSPRevocationStatus() {

@Override
Expand All @@ -102,7 +135,7 @@ public Date getRevocationTime() {
public CRLReason getRevocationReason() {
return null;
}

};
}

Expand Down Expand Up @@ -155,6 +188,7 @@ protected List<String> getResponderURIs(X509Certificate cert) throws Certificate
}
}

logger.warn("OCSP Responder URIs" + Arrays.toString(responderURIs.toArray()));
return responderURIs;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -39,16 +39,21 @@
*/
public class ElytronUserIdentityExtractorProvider extends UserIdentityExtractorProvider {

private static final Logger logger = Logger.getLogger(ElytronUserIdentityExtractorProvider.class.getName());
private Logger log = Logger.getLogger(this.getClass());

class X500NameRDNExtractorElytronProvider extends X500NameRDNExtractor {

private String x500NameStyle;
Function<X509Certificate[],Principal> x500Name;

public X500NameRDNExtractorElytronProvider(String attrName, Function<X509Certificate[], Principal> x500Name) {
//this.x500NameStyle = BCStyle.INSTANCE.attrNameToOID(attrName);
// The OidsUtil fails to map 'EmailAddress', instead 'E' is mapped to the OID.
// TODO: Open an issue with wildfly-elytron to include 'EmailAddress' in the oid mapping
if(attrName.equals("EmailAddress")) {
attrName = "E";
}
this.x500NameStyle = OidsUtil.attributeNameToOid(OidsUtil.Category.RDN, attrName);
log.debug("Attribute Name: " + attrName + " X500NameStyle OID: " + x500NameStyle);
this.x500Name = x500Name;
}

Expand All @@ -59,6 +64,7 @@ public Object extractUserIdentity(X509Certificate[] certs) {
throw new IllegalArgumentException();

Principal name = x500Name.apply(certs);
log.debug("Principal Name " + name.getName());
X500AttributePrincipalDecoder xDecoder = new X500AttributePrincipalDecoder(x500NameStyle);
String cn = xDecoder.apply(name);

Expand Down Expand Up @@ -95,29 +101,28 @@ public Object extractUserIdentity(X509Certificate[] certs) {
}
String subjectName = null;

logger.info("SubjPrinc " + certs[0].getSubjectX500Principal());
log.debug("SubjPrinc " + certs[0].getSubjectX500Principal());
Collection<List<?>> subjectAlternativeNames;
try {
subjectAlternativeNames = certs[0].getSubjectAlternativeNames();
if (subjectAlternativeNames == null) {
return null;
}
log.info(Arrays.toString(subjectAlternativeNames.toArray()));
for (List<?> sbjAltName : subjectAlternativeNames) {
if (sbjAltName == null)
continue;

Integer nameType = (Integer) sbjAltName.get(0);

if (nameType == generalName) {
logger.info("sbjAltName Type " + nameType);
logger.info("sbjAltName[1]: " + sbjAltName.get(1));

Object sbjObj = sbjAltName.get(1);

switch (nameType) {
case GeneralName.RFC_822_NAME:
case GeneralName.DNS_NAME:
case GeneralName.DIRECTORY_NAME:
case GeneralName.URI_NAME:
subjectName = (String) sbjObj;
break;
case GeneralName.OTHER_NAME:
Expand All @@ -126,12 +131,12 @@ public Object extractUserIdentity(X509Certificate[] certs) {
boolean upnOidFound = false;
while (derDecoder.hasNextElement() && !upnOidFound) {
int asn1Type = derDecoder.peekType();
logger.info("ASN.1 Type: " + derDecoder.peekType());
log.debug("ASN.1 Type: " + derDecoder.peekType());

switch (asn1Type) {
case ASN1.OBJECT_IDENTIFIER_TYPE:
String oid = derDecoder.decodeObjectIdentifier();
logger.info("OID: " + oid);
log.debug("OID: " + oid);
if(UPN_OID.equals(oid)) {
derDecoder.decodeImplicit(160);
byte[] sb = derDecoder.drainElementValue();
Expand All @@ -154,22 +159,28 @@ public Object extractUserIdentity(X509Certificate[] certs) {
case ASN1.OCTET_STRING_TYPE:
subjectName = derDecoder.decodeOctetStringAsString();
break;
case 0xa0:
derDecoder.startExplicit(asn1Type);
break;
case ASN1.SEQUENCE_TYPE:
derDecoder.startSequence();
default:
derDecoder.skipElement();

}


}
logger.info("Subject Alt Name: " + subjectName);
}

}

}
} catch (CertificateParsingException | UnsupportedEncodingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
log.error("Failed to parse Subject Name:",e);
}


log.debug("Subject Alt Name: " + subjectName);
return subjectName;
}
}
Expand Down
Loading

0 comments on commit ef203b7

Please sign in to comment.