From e7f8f29c4f8105c4c94a8dadb10a2f6a8d41ea8d Mon Sep 17 00:00:00 2001 From: kares Date: Tue, 5 Oct 2021 13:21:05 +0200 Subject: [PATCH 01/63] prepare for support of V_FLAG_TRUSTED_FIRST --- .../ext/openssl/x509store/StoreContext.java | 52 +++++++++++++++---- .../ext/openssl/x509store/X509Error.java | 10 +++- .../ext/openssl/x509store/X509Utils.java | 45 +++++++++++++--- 3 files changed, 87 insertions(+), 20 deletions(-) diff --git a/src/main/java/org/jruby/ext/openssl/x509store/StoreContext.java b/src/main/java/org/jruby/ext/openssl/x509store/StoreContext.java index 235fcc40..e20e8b80 100644 --- a/src/main/java/org/jruby/ext/openssl/x509store/StoreContext.java +++ b/src/main/java/org/jruby/ext/openssl/x509store/StoreContext.java @@ -45,6 +45,9 @@ import org.bouncycastle.asn1.ASN1Sequence; import org.jruby.ext.openssl.SecurityHelper; +import static org.jruby.ext.openssl.x509store.X509Error.addError; +import static org.jruby.ext.openssl.x509store.X509Utils.*; + /** * c: X509_STORE_CTX * @@ -638,24 +641,54 @@ else if( j > 0 ) { * c: X509_verify_cert */ public int verifyCertificate() throws Exception { - X509AuxCertificate x, xtmp = null, chain_ss = null; - //X509_NAME xn; - int bad_chain = 0, depth, i, num; - if ( certificate == null ) { - X509Error.addError(X509Utils.X509_R_NO_CERT_SET_FOR_US_TO_VERIFY); + addError(X509_R_NO_CERT_SET_FOR_US_TO_VERIFY); + this.error = X509Utils.V_ERR_INVALID_CALL; return -1; } - // first we make sure the chain we are going to build is - // present and that the first entry is in place + if ( chain != null ) { + /* + * This X509_STORE_CTX has already been used to verify a cert. We cannot do another one. + */ + addError(ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); + this.error = X509Utils.V_ERR_INVALID_CALL; + return -1; + } + /* + * first we make sure the chain we are going to build is present and that + * the first entry is in place + */ if ( chain == null ) { - chain = new ArrayList(); + chain = new ArrayList(8); chain.add(certificate); lastUntrusted = 1; } + // TODO not implemented: + /* If the peer's public key is too weak, we can stop early. */ + + int ret = verifyChain(); + + /* + * Safety-net. If we are returning an error, we must also set ctx->error, + * so that the chain is not considered verified should the error be ignored + * (e.g. TLS with SSL_VERIFY_NONE). + */ + if (ret <= 0 && this.error == V_OK) { + this.error = V_ERR_UNSPECIFIED; + } + return ret; + } + + /** + * c: verify_chain + */ + private int verifyChain() throws Exception { + X509AuxCertificate x, xtmp = null, chain_ss = null; + int bad_chain = 0, depth, i, num; + // We use a temporary STACK so we can chop and hack at it List sktmp = null; @@ -750,7 +783,7 @@ public int verifyCertificate() throws Exception { /* Is last certificate looked up self signed? */ if ( checkIssued.call(this, x, x) == 0 ) { if ( chain_ss == null || checkIssued.call(this, x, chain_ss) == 0 ) { - if(lastUntrusted >= num) { + if (lastUntrusted >= num) { error = X509Utils.V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY; } else { error = X509Utils.V_ERR_UNABLE_TO_GET_ISSUER_CERT; @@ -801,7 +834,6 @@ public int verifyCertificate() throws Exception { return ok; } - private final static Set CRITICAL_EXTENSIONS = new HashSet(8); static { CRITICAL_EXTENSIONS.add("2.16.840.1.113730.1.1"); // netscape cert type, NID 71 diff --git a/src/main/java/org/jruby/ext/openssl/x509store/X509Error.java b/src/main/java/org/jruby/ext/openssl/x509store/X509Error.java index be3a3856..62081cdb 100644 --- a/src/main/java/org/jruby/ext/openssl/x509store/X509Error.java +++ b/src/main/java/org/jruby/ext/openssl/x509store/X509Error.java @@ -100,12 +100,17 @@ public static String getMessage(int reason) { } } - private static ThreadLocal> errors = new ThreadLocal>(); + private static final ThreadLocal> errors = new ThreadLocal>(); public static void addError(int reason) { getErrors().put(reason, getMessage(reason)); } + // define X509err(f, r) ERR_raise_data(ERR_LIB_X509, (r), NULL) + //public static void addError(int f, int r) { + // getErrors().put(r, getMessage(r)); + //} + public static void clearErrors() { synchronized (errors) { if ( errors.get() != null ) newErrorsMap(); @@ -144,7 +149,8 @@ public static Map getErrorsImpl(boolean required) { private static Map newErrorsMap() { Map map = new LinkedHashMap(8); - errors.set(map); return map; + errors.set(map); + return map; } }// Err diff --git a/src/main/java/org/jruby/ext/openssl/x509store/X509Utils.java b/src/main/java/org/jruby/ext/openssl/x509store/X509Utils.java index a1980e8e..9defd437 100644 --- a/src/main/java/org/jruby/ext/openssl/x509store/X509Utils.java +++ b/src/main/java/org/jruby/ext/openssl/x509store/X509Utils.java @@ -365,6 +365,7 @@ else if (maybeCertFile != null && new File(maybeCertFile).exists()) { public static final int X509_L_ADD_DIR = 2; public static final int V_OK = 0; + public static final int V_ERR_UNSPECIFIED = 1; public static final int V_ERR_UNABLE_TO_GET_ISSUER_CERT = 2; public static final int V_ERR_UNABLE_TO_GET_CRL = 3; public static final int V_ERR_UNABLE_TO_DECRYPT_CERT_SIGNATURE = 4; @@ -413,25 +414,53 @@ else if (maybeCertFile != null && new File(maybeCertFile).exists()) { public static final int V_ERR_APPLICATION_VERIFICATION = 50; - public static final int V_FLAG_CB_ISSUER_CHECK = 0x1; + // ... + + /* security level errors */ + //public static final int V_ERR_EE_KEY_TOO_SMALL = 66; + //public static final int V_ERR_CA_KEY_TOO_SMALL = 67; + //public static final int V_ERR_CA_MD_TOO_WEAK = 68; + /* Caller error */ + public static final int V_ERR_INVALID_CALL = 69; + /* Issuer lookup error */ + //public static final int V_ERR_STORE_LOOKUP = 70; + /* Certificate transparency */ + //public static final int V_ERR_NO_VALID_SCTS = 71; + + /* Certificate verify flags */ + public static final int V_FLAG_CB_ISSUER_CHECK = 0x0 /* Deprecated */; public static final int V_FLAG_USE_CHECK_TIME = 0x2; public static final int V_FLAG_CRL_CHECK = 0x4; public static final int V_FLAG_CRL_CHECK_ALL = 0x8; public static final int V_FLAG_IGNORE_CRITICAL = 0x10; - public static final int V_FLAG_STRICT = 0x20; - public static final int V_FLAG_X509_STRICT = 0x20; + public static final int V_FLAG_X509_STRICT = 0x20; public static final int V_FLAG_ALLOW_PROXY_CERTS = 0x40; public static final int V_FLAG_POLICY_CHECK = 0x80; public static final int V_FLAG_EXPLICIT_POLICY = 0x100; public static final int V_FLAG_INHIBIT_ANY = 0x200; public static final int V_FLAG_INHIBIT_MAP = 0x400; public static final int V_FLAG_NOTIFY_POLICY = 0x800; + // NOTE: these aren't implemented: + /* Extended CRL features such as indirect CRLs, alternate CRL signing keys */ + //public static final int V_FLAG_EXTENDED_CRL_SUPPORT = 0x1000; + /* Delta CRL support */ + //public static final int V_FLAG_USE_DELTAS = 0x2000; + /* Check self-signed CA signature */ + //public static final int V_FLAG_CHECK_SS_SIGNATURE = 0x4000; + /* Use trusted store first */ + public static final int V_FLAG_TRUSTED_FIRST = 0x8000; + + // ... + + /* Allow partial chains if at least one certificate is in trusted store */ + public static final int V_FLAG_PARTIAL_CHAIN = 0x80000; + /* + * If the initial chain is not trusted, do not attempt to build an alternative + * chain. Alternate chain checking was introduced in 1.1.0. Setting this flag + * will force the behaviour to match that of previous versions. + */ + //public static final int V_FLAG_NO_ALT_CHAINS = 0x100000; - public static final int VP_FLAG_DEFAULT = 0x1; - public static final int VP_FLAG_OVERWRITE = 0x2; - public static final int VP_FLAG_RESET_FLAGS = 0x4; - public static final int VP_FLAG_LOCKED = 0x8; - public static final int VP_FLAG_ONCE = 0x10; /* Internal use: mask of policy related options */ public static final int V_FLAG_POLICY_MASK = (V_FLAG_POLICY_CHECK | From 49c2a2cb64e24fd2f679cdf81266a5eac78f5727 Mon Sep 17 00:00:00 2001 From: kares Date: Tue, 5 Oct 2021 17:06:47 +0200 Subject: [PATCH 02/63] port over build_chain etc (from OpenSSL 1.1) --- .../ext/openssl/x509store/StoreContext.java | 348 +++++++++++++++++- .../ext/openssl/x509store/X509Utils.java | 4 +- 2 files changed, 347 insertions(+), 5 deletions(-) diff --git a/src/main/java/org/jruby/ext/openssl/x509store/StoreContext.java b/src/main/java/org/jruby/ext/openssl/x509store/StoreContext.java index e20e8b80..ef271373 100644 --- a/src/main/java/org/jruby/ext/openssl/x509store/StoreContext.java +++ b/src/main/java/org/jruby/ext/openssl/x509store/StoreContext.java @@ -834,6 +834,335 @@ private int verifyChain() throws Exception { return ok; } + private static final short S_DOUNTRUSTED = (1 << 0); /* Search untrusted chain */ + private static final short S_DOTRUSTED = (1 << 1); /* Search trusted store */ + private static final short S_DOALTERNATE = (1 << 2); /* Retry with pruned alternate chain */ + + /* + * x509_vfy.c: static int build_chain(X509_STORE_CTX *ctx) + */ + int build_chain() throws Exception { + int num = chain.size(); + X509AuxCertificate cert = chain.get(num - 1); + boolean ss = checkIssued.call(this, cert, cert) != 0; // cert_self_signed(cert) + short search; + boolean may_trusted = false; + boolean may_alternate = false; + int trust = X509_TRUST_UNTRUSTED; + int alt_untrusted = 0; + int depth; + int ok = 0; + int i; + + /* + * Set up search policy, untrusted if possible, trusted-first if enabled. + * If we're doing DANE and not doing PKIX-TA/PKIX-EE, we never look in the + * trust_store, otherwise we might look there first. If not trusted-first, + * and alternate chains are not disabled, try building an alternate chain + * if no luck with untrusted first. + */ + search = untrusted != null ? S_DOUNTRUSTED : 0; + //if (DANETLS_HAS_PKIX(dane) || !DANETLS_HAS_DANE(dane)) { + if (search == 0 || (getParam().flags & V_FLAG_TRUSTED_FIRST) != 0) { + search |= S_DOTRUSTED; + } else if ((getParam().flags & V_FLAG_NO_ALT_CHAINS) == 0) { + may_alternate = true; + } + may_trusted = true; + //} + + /* + * Shallow-copy the stack of untrusted certificates (with TLS, this is + * typically the content of the peer's certificate message) so can make + * multiple passes over it, while free to remove elements as we go. + */ + ArrayList sktmp = untrusted != null ? new ArrayList<>(untrusted) : null; + + depth = verifyParameter.depth; + + /* + * Still absurdly large, but arithmetically safe, a lower hard upper bound + * might be reasonable. + */ + if (depth > Integer.MAX_VALUE / 2) depth = Integer.MAX_VALUE / 2; + + /* + * Try to Extend the chain until we reach an ultimately trusted issuer. + * Build chains up to one longer the limit, later fail if we hit the limit, + * with an X509_V_ERR_CERT_CHAIN_TOO_LONG error code. + */ + depth = depth + 1; + + while (search != 0) { + X509AuxCertificate x, xtmp = null; + + /* + * Look in the trust store if enabled for first lookup, or we've run + * out of untrusted issuers and search here is not disabled. When we + * reach the depth limit, we stop extending the chain, if by that point + * we've not found a trust-anchor, any trusted chain would be too long. + * + * The error reported to the application verify callback is at the + * maximal valid depth with the current certificate equal to the last + * not ultimately-trusted issuer. For example, with verify_depth = 0, + * the callback will report errors at depth=1 when the immediate issuer + * of the leaf certificate is not a trust anchor. No attempt will be + * made to locate an issuer for that certificate, since such a chain + * would be a-priori too long. + */ + if ((search & S_DOTRUSTED) != 0) { + i = num = chain.size(); + if ((search & S_DOALTERNATE) != 0) { + /* + * As high up the chain as we can, look for an alternative + * trusted issuer of an untrusted certificate that currently + * has an untrusted issuer. We use the alt_untrusted variable + * to track how far up the chain we find the first match. It + * is only if and when we find a match, that we prune the chain + * and reset ctx->num_untrusted to the reduced count of + * untrusted certificates. While we're searching for such a + * match (which may never be found), it is neither safe nor + * wise to preemptively modify either the chain or + * ctx->num_untrusted. + * + * Note, like ctx->num_untrusted, alt_untrusted is a count of + * untrusted certificates, not a "depth". + */ + i = alt_untrusted; + } + x = chain.get(i - 1); + + X509AuxCertificate[] p_xtmp = new X509AuxCertificate[] { xtmp }; + ok = (depth < num) ? 0 : getIssuer.call(this, p_xtmp, x); // get_issuer(&xtmp, ctx, x) + xtmp = p_xtmp[0]; + + if (ok < 0) { + trust = X509_TRUST_REJECTED; + this.error = V_ERR_STORE_LOOKUP; + search = 0; + continue; + } + + if (ok > 0) { + /* + * Alternative trusted issuer for a mid-chain untrusted cert? + * Pop the untrusted cert's successors and retry. We might now + * be able to complete a valid chain via the trust store. Note + * that despite the current trust-store match we might still + * fail complete the chain to a suitable trust-anchor, in which + * case we may prune some more untrusted certificates and try + * again. Thus the S_DOALTERNATE bit may yet be turned on + * again with an even shorter untrusted chain! + * + * We might find a suitable trusted certificate among the ones from the trust store. + */ + if ((search & S_DOALTERNATE) != 0) { + if (!(num > i && i > 0 && ss == false)) { // ossl_assert + addError(ERR_R_INTERNAL_ERROR); + trust = X509_TRUST_REJECTED; + this.error = V_ERR_UNSPECIFIED; + search = 0; + continue; + } + search &= ~S_DOALTERNATE; + for (; num > i; --num) chain.remove(chain.size() - 1); // pop + num_untrusted = num; + } + + /* + * Self-signed untrusted certificates get replaced by their + * trusted matching issuer. Otherwise, grow the chain. + */ + if (ss == false) { + chain.add(x = xtmp); + ss = checkIssued.call(this, x, x) != 0; // cert_self_signed(x) + } else if (num == num_untrusted) { + /* + * We have a self-signed certificate that has the same + * subject name (and perhaps keyid and/or serial number) as + * a trust-anchor. We must have an exact match to avoid + * possible impersonation via key substitution etc. + */ + if (!x.equals(xtmp)) { + /* Self-signed untrusted mimic. */ + xtmp = null; + ok = 0; + } else { + num_untrusted = --num; + chain.set(num, x = xtmp); + } + } + + /* + * We've added a new trusted certificate to the chain, recheck + * trust. If not done, and not self-signed look deeper. + * Whether or not we're doing "trusted first", we no longer + * look for untrusted certificates from the peer's chain. + * + * At this point ctx->num_trusted and num must reflect the + * correct number of untrusted certificates, since the DANE + * logic in check_trust() depends on distinguishing CAs from + * "the wire" from CAs from the trust store. In particular, the + * certificate at depth "num" should be the new trusted + * certificate with ctx->num_untrusted <= num. + */ + if (ok != 0) { + if (!(num_untrusted <= num)) { // ossl_assert + addError(ERR_R_INTERNAL_ERROR); + trust = X509_TRUST_REJECTED; + this.error = V_ERR_UNSPECIFIED; + search = 0; + continue; + } + search &= ~S_DOUNTRUSTED; + switch (trust = check_trust(num)) { + case X509_TRUST_TRUSTED: + case X509_TRUST_REJECTED: + search = 0; + continue; + } + if (ss == false) continue; + } + } + + /* + * No dispositive decision, and either self-signed or no match, if + * we were doing untrusted-first, and alt-chains are not disabled, + * do that, by repeatedly losing one untrusted element at a time, + * and trying to extend the shorted chain. + */ + if ((search & S_DOUNTRUSTED) == 0) { + /* Continue search for a trusted issuer of a shorter chain? */ + if ((search & S_DOALTERNATE) != 0 && --alt_untrusted > 0) + continue; + /* Still no luck and no fallbacks left? */ + if (!may_alternate || (search & S_DOALTERNATE) != 0 || num_untrusted < 2) + break; + /* Search for a trusted issuer of a shorter chain */ + search |= S_DOALTERNATE; + alt_untrusted = num_untrusted - 1; + ss = false; + } + } + + /* + * Extend chain with peer-provided certificates + */ + if ((search & S_DOUNTRUSTED) != 0) { + num = chain.size(); + if (!(num == num_untrusted)) { // ossl_assert + addError(ERR_R_INTERNAL_ERROR); + trust = X509_TRUST_REJECTED; + this.error = V_ERR_UNSPECIFIED; + search = 0; + continue; + } + x = chain.get(num-1); + + /* + * Once we run out of untrusted issuers, we stop looking for more + * and start looking only in the trust store if enabled. + */ + xtmp = (ss || depth < num) ? null : find_issuer(ctx, sktmp, x); + if (xtmp == null) { + search &= ~S_DOUNTRUSTED; + if (may_trusted) search |= S_DOTRUSTED; + continue; + } + + /* Drop this issuer from future consideration */ + sktmp.remove(xtmp); + + chain.add(xtmp); + + x = xtmp; + num_untrusted++; + ss = checkIssued.call(this, xtmp, xtmp) != 0; // cert_self_signed(xtmp) + + } + } + // sk_X509_free(sktmp) + + /* + * Last chance to make a trusted chain, either bare DANE-TA public-key + * signers, or else direct leaf PKIX trust. + */ + num = chain.size(); + if (num <= depth) { + if (trust == X509_TRUST_UNTRUSTED && num == num_untrusted) { + trust = check_trust(num); + } + } + + switch (trust) { + case X509_TRUST_TRUSTED: + return 1; + case X509_TRUST_REJECTED: + /* Callback already issued */ + return 0; + case X509_TRUST_UNTRUSTED: + default: + num = chain.size(); + if (num > depth) { + return verify_cb_cert(null, num - 1, V_ERR_CERT_CHAIN_TOO_LONG); + } + if (ss && num == 1) + return verify_cb_cert(null, num - 1, V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT); + if (ss) { + return verify_cb_cert(null, num - 1, V_ERR_SELF_SIGNED_CERT_IN_CHAIN); + } + if (num_untrusted < num) { + return verify_cb_cert(null, num - 1, V_ERR_UNABLE_TO_GET_ISSUER_CERT); + } + return verify_cb_cert(null, num-1, V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY); + } + } + + /* + * Given a STACK_OF(X509) find the issuer of cert (if any) + * + * x509_vfy.c: static int build_chain(X509_STORE_CTX *ctx) + */ + private X509AuxCertificate find_issuer(List sk, X509AuxCertificate x) throws Exception { + X509AuxCertificate rv = null; + + for (int i = 0; i < sk.size(); i++) { + X509AuxCertificate issuer = sk.get(i); + if (check_issued(x, issuer)) { + rv = issuer; + if (x509_check_cert_time(ctx, rv, -1)) + break; + } + } + return rv; + } + + /* + * Given a possible certificate and issuer check them + * + * x509_vfy.c: static int check_issued(X509_STORE_CTX *ctx, X509 *x, X509 *issuer) + */ + private boolean check_issued(X509AuxCertificate x, X509AuxCertificate issuer) throws Exception { + int ret; + if (x == issuer) return checkIssued.call(this, x, x) != 0; // cert_self_signed(x) + ret = checkIfIssuedBy(issuer, x); + if (ret == V_OK) { + /* Special case: single self signed certificate */ + boolean ss = checkIssued.call(this, x, x) != 0; // cert_self_signed(x) + if (ss && chain.size() == 1) return true; + + //for (int i = 0; i < chain.size(); i++) { + // X509AuxCertificate ch = chain.get(i); + // if (ch == issuer || ch.equals(issuer)) { + // ret = V_ERR_PATH_LOOP; + // break; + // } + //} + } + + return (ret == V_OK); + } + private final static Set CRITICAL_EXTENSIONS = new HashSet(8); static { CRITICAL_EXTENSIONS.add("2.16.840.1.113730.1.1"); // netscape cert type, NID 71 @@ -970,9 +1299,6 @@ public int checkChainExtensions() throws Exception { return 1; } - /** - * c: X509_check_trust - */ public int checkTrust() throws Exception { int i,ok; X509AuxCertificate x; @@ -1100,6 +1426,22 @@ public int getCRLStack(X509CRL[] pcrl, Name name, List crls) throws Exc return 0; } + /* + * Inform the verify callback of an error. + * If B is not NULL it is the error cert, otherwise use the chain cert at + * B. + * If B is not X509_V_OK, that's the error value, otherwise leave + * unchanged (presumably set by the caller). + * + * Returns 0 to abort verification with an error, non-zero to continue. + */ + private int verify_cb_cert(X509AuxCertificate x, int depth, int err) throws Exception { + this.errorDepth = depth; + this.currentCertificate = x != null ? x : chain.get(depth); + if (err != V_OK) this.error = err; + return verifyCallback.call(this, 0); // ctx->verify_cb(0, ctx) + } + final static Store.GetIssuerFunction getFirstIssuer = new Store.GetIssuerFunction() { public int call(StoreContext context, X509AuxCertificate[] issuer, X509AuxCertificate cert) throws Exception { return context.getFirstIssuer(issuer, cert); diff --git a/src/main/java/org/jruby/ext/openssl/x509store/X509Utils.java b/src/main/java/org/jruby/ext/openssl/x509store/X509Utils.java index 9defd437..e9a4252e 100644 --- a/src/main/java/org/jruby/ext/openssl/x509store/X509Utils.java +++ b/src/main/java/org/jruby/ext/openssl/x509store/X509Utils.java @@ -423,7 +423,7 @@ else if (maybeCertFile != null && new File(maybeCertFile).exists()) { /* Caller error */ public static final int V_ERR_INVALID_CALL = 69; /* Issuer lookup error */ - //public static final int V_ERR_STORE_LOOKUP = 70; + public static final int V_ERR_STORE_LOOKUP = 70; /* Certificate transparency */ //public static final int V_ERR_NO_VALID_SCTS = 71; @@ -459,7 +459,7 @@ else if (maybeCertFile != null && new File(maybeCertFile).exists()) { * chain. Alternate chain checking was introduced in 1.1.0. Setting this flag * will force the behaviour to match that of previous versions. */ - //public static final int V_FLAG_NO_ALT_CHAINS = 0x100000; + public static final int V_FLAG_NO_ALT_CHAINS = 0x100000; /* Internal use: mask of policy related options */ From ab2f06f9093ec3413542a2ee9a086f7817c0dcae Mon Sep 17 00:00:00 2001 From: kares Date: Wed, 6 Oct 2021 11:38:09 +0200 Subject: [PATCH 03/63] Refactor: house-keeping --- .../jruby/ext/openssl/x509store/StoreContext.java | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/src/main/java/org/jruby/ext/openssl/x509store/StoreContext.java b/src/main/java/org/jruby/ext/openssl/x509store/StoreContext.java index ef271373..a10dd311 100644 --- a/src/main/java/org/jruby/ext/openssl/x509store/StoreContext.java +++ b/src/main/java/org/jruby/ext/openssl/x509store/StoreContext.java @@ -73,13 +73,7 @@ public StoreContext(final Store store) { this.store = store; } - public static interface CheckPolicyFunction extends Function1 { - public static final CheckPolicyFunction EMPTY = new CheckPolicyFunction(){ - public int call(StoreContext context) { - return -1; - } - }; - } + interface CheckPolicyFunction extends Function1 {} Store.VerifyFunction verify; Store.VerifyCallbackFunction verifyCallback; @@ -610,7 +604,7 @@ public int setDefault(String name) { /** * c: X509_STORE_get_by_subject (it gets X509_STORE_CTX as the first parameter) */ - public int getBySubject(int type,Name name,X509Object[] ret) throws Exception { + public int getBySubject(int type, Name name, X509Object[] ret) throws Exception { Store c = store; X509Object tmp = X509Object.retrieveBySubject(c.getObjects(),type,name); @@ -619,7 +613,7 @@ public int getBySubject(int type,Name name,X509Object[] ret) throws Exception { for(int i=currentMethod; i Date: Wed, 6 Oct 2021 11:41:40 +0200 Subject: [PATCH 04/63] missing num_untrusted field + more porting from 1.1 --- .../ext/openssl/x509store/StoreContext.java | 198 +++++++++++++++++- 1 file changed, 193 insertions(+), 5 deletions(-) diff --git a/src/main/java/org/jruby/ext/openssl/x509store/StoreContext.java b/src/main/java/org/jruby/ext/openssl/x509store/StoreContext.java index a10dd311..b933c306 100644 --- a/src/main/java/org/jruby/ext/openssl/x509store/StoreContext.java +++ b/src/main/java/org/jruby/ext/openssl/x509store/StoreContext.java @@ -89,8 +89,11 @@ interface CheckPolicyFunction extends Function1 {} public boolean isValid; public int lastUntrusted; - public List chain; //List - public PolicyTree tree; + + private int num_untrusted; + + private ArrayList chain; + private PolicyTree tree; public int explicitPolicy; @@ -905,7 +908,7 @@ int build_chain() throws Exception { * would be a-priori too long. */ if ((search & S_DOTRUSTED) != 0) { - i = num = chain.size(); + int i = num = chain.size(); if ((search & S_DOALTERNATE) != 0) { /* * As high up the chain as we can, look for an alternative @@ -1057,7 +1060,7 @@ int build_chain() throws Exception { * Once we run out of untrusted issuers, we stop looking for more * and start looking only in the trust store if enabled. */ - xtmp = (ss || depth < num) ? null : find_issuer(ctx, sktmp, x); + xtmp = (ss || depth < num) ? null : find_issuer(sktmp, x); if (xtmp == null) { search &= ~S_DOUNTRUSTED; if (may_trusted) search |= S_DOTRUSTED; @@ -1108,7 +1111,7 @@ int build_chain() throws Exception { if (num_untrusted < num) { return verify_cb_cert(null, num - 1, V_ERR_UNABLE_TO_GET_ISSUER_CERT); } - return verify_cb_cert(null, num-1, V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY); + return verify_cb_cert(null, num - 1, V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY); } } @@ -1293,6 +1296,191 @@ public int checkChainExtensions() throws Exception { return 1; } + /* + * Check EE or CA certificate purpose. For trusted certificates explicit local + * auxiliary trust can be used to override EKU-restrictions. + * + * x509_vfy.c: static int check_purpose(X509_STORE_CTX *ctx, X509 *x, int purpose, int depth, int must_be_ca) + */ + private int check_purpose(X509AuxCertificate x, int purpose, int depth, byte must_be_ca) throws Exception { + int tr_ok = X509_TRUST_UNTRUSTED; + + /* + * For trusted certificates we want to see whether any auxiliary trust + * settings trump the purpose constraints. + * + * This is complicated by the fact that the trust ordinals in + * ctx->param->trust are entirely independent of the purpose ordinals in + * ctx->param->purpose! + * + * What connects them is their mutual initialization via calls from + * X509_STORE_CTX_set_default() into X509_VERIFY_PARAM_lookup() which sets + * related values of both param->trust and param->purpose. It is however + * typically possible to infer associated trust values from a purpose value + * via the X509_PURPOSE API. + * + * Therefore, we can only check for trust overrides when the purpose we're + * checking is the same as ctx->param->purpose and ctx->param->trust is + * also set. + */ + if (depth >= num_untrusted && purpose == getParam().purpose) { + tr_ok = Trust.checkTrust(x, getParam().trust, X509_TRUST_NO_SS_COMPAT); // X509_check_trust + } + + switch (tr_ok) { + case X509_TRUST_TRUSTED: + return 1; + case X509_TRUST_REJECTED: + break; + default: + // TODO X509_check_purpose(x, purpose, must_be_ca) passing down must_be_ca == -1 + switch (Purpose.checkPurpose(x, verifyParameter.purpose, must_be_ca > 0 ? 1 : 0)) { // X509_check_purpose(x, purpose, must_be_ca) + case 1: + return 1; + case 0: + break; + default: + if ((getParam().flags & V_FLAG_X509_STRICT) == 0) return 1; + } + break; + } + + return verify_cb_cert(x, depth, V_ERR_INVALID_PURPOSE); + } + + /* + * Check a certificate chains extensions for consistency with the supplied purpose + * + * static int check_chain_extensions(X509_STORE_CTX *ctx) + */ + private int check_chain_extensions() throws Exception { + byte must_be_ca, int plen = 0; + X509AuxCertificate x; + int proxy_path_length = 0; + int purpose; + boolean allow_proxy_certs; + int num = chain.size(); + + /*- + * must_be_ca can have 1 of 3 values: + * -1: we accept both CA and non-CA certificates, to allow direct + * use of self-signed certificates (which are marked as CA). + * 0: we only accept non-CA certificates. This is currently not + * used, but the possibility is present for future extensions. + * 1: we only accept CA certificates. This is currently used for + * all certificates in the chain except the leaf certificate. + */ + must_be_ca = -1; + + /* CRL path validation */ + //if (ctx->parent) { // todo this.parent not implemented + // allow_proxy_certs = 0; + // purpose = X509_PURPOSE_CRL_SIGN; + //} else { + allow_proxy_certs = (getParam().flags & V_FLAG_ALLOW_PROXY_CERTS) != 0; + purpose = getParam().purpose; + //} + + for (int i = 0; i < num; i++) { + int ret; + x = chain.get(i); + if ((getParam().flags & V_FLAG_IGNORE_CRITICAL) == 0 && unhandledCritical(x)) { + if (verify_cb_cert(x, i, V_ERR_UNHANDLED_CRITICAL_EXTENSION) == 0) + return 0; + } + if (allow_proxy_certs == false && x.getExtensionValue("1.3.6.1.5.5.7.1.14") != null) { // && (x->ex_flags & EXFLAG_PROXY) + if (verify_cb_cert(x, i, V_ERR_PROXY_CERTIFICATES_NOT_ALLOWED) == 0) + return 0; + } + ret = Purpose.checkCA(x); // X509_check_ca(x) + switch (must_be_ca) { + case -1: + if ((getParam().flags & V_FLAG_X509_STRICT) != 0 && ret != 1 && ret != 0) { + ret = 0; + this.error = V_ERR_INVALID_CA; + } else { + ret = 1; + } + break; + case 0: + if (ret != 0) { + ret = 0; + this.error = V_ERR_INVALID_NON_CA; + } else { + ret = 1; + } + break; + default: + /* X509_V_FLAG_X509_STRICT is implicit for intermediate CAs */ + if ((ret == 0) || ((i + 1 < num || (getParam().flags & V_FLAG_X509_STRICT) != 0) + && (ret != 1))) { + ret = 0; + this.error = V_ERR_INVALID_CA; + } else + ret = 1; + break; + } + + if (ret == 0 && verify_cb_cert(x, i, V_OK) == 0) + return 0; + /* check_purpose() makes the callback as needed */ + if (purpose > 0 && check_purpose(x, purpose, i, must_be_ca) == 0) + return 0; + /* Check pathlen if not self issued */ + final int ex_pathlen = x.getBasicConstraints(); + if ((i > 1) && ex_pathlen != Integer.MAX_VALUE // !(x->ex_flags & EXFLAG_SI) + && ex_pathlen != -1 + && (plen > (ex_pathlen + proxy_path_length + 1))) { + if (verify_cb_cert(x, i, V_ERR_PATH_LENGTH_EXCEEDED) == 0) + return 0; + } + + /* Increment path length if not self issued */ + if (!isSelfIssued(x)) plen++; + + /* + * If this certificate is a proxy certificate, the next certificate + * must be another proxy certificate or a EE certificate. If not, + * the next certificate must be a CA certificate. + */ + final byte[] ex_proxyCertInfo = x.getExtensionValue("1.3.6.1.5.5.7.1.14"); // id-pe-proxyCertInfo(14) + if (ex_proxyCertInfo != null) { // x->ex_flags & EXFLAG_PROXY + ASN1Sequence pci = (ASN1Sequence) new ASN1InputStream(ex_proxyCertInfo).readObject(); + if (pci.size() > 0 && pci.getObjectAt(0) instanceof ASN1Integer) { + int ex_pcpathlen = ((ASN1Integer) pci.getObjectAt(0)).getValue().intValue(); + /* + * RFC3820, 4.1.3 (b)(1) stipulates that if pCPathLengthConstraint + * is less than max_path_length, the former should be copied to + * the latter, and 4.1.4 (a) stipulates that max_path_length + * should be verified to be larger than zero and decrement it. + * + * Because we're checking the certs in the reverse order, we start + * with verifying that proxy_path_length isn't larger than pcPLC, + * and copy the latter to the former if it is, and finally, + * increment proxy_path_length. + */ + if (ex_pcpathlen != -1) { + if (proxy_path_length > ex_pcpathlen) { + if (verify_cb_cert(x, i, V_ERR_PROXY_PATH_LENGTH_EXCEEDED) == 0) + return 0; + } + proxy_path_length = ex_pcpathlen; + } + } + proxy_path_length++; + must_be_ca = 0; + } else { + must_be_ca = 1; + } + } + return 1; + } + + private boolean isSelfIssued(final X509AuxCertificate x) throws Exception { + // (x->ex_flags & EXFLAG_SI)) + return checkIssued.call(this, x, x) != 0; // TODO self-signed == self-issued? + } + public int checkTrust() throws Exception { int i,ok; X509AuxCertificate x; From 99f96110682ffc2521bd8552234558958ebf4958 Mon Sep 17 00:00:00 2001 From: kares Date: Wed, 6 Oct 2021 11:42:33 +0200 Subject: [PATCH 05/63] Refactor: use a LinkedList instead --- .../ext/openssl/x509store/StoreContext.java | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/src/main/java/org/jruby/ext/openssl/x509store/StoreContext.java b/src/main/java/org/jruby/ext/openssl/x509store/StoreContext.java index b933c306..8eab997a 100644 --- a/src/main/java/org/jruby/ext/openssl/x509store/StoreContext.java +++ b/src/main/java/org/jruby/ext/openssl/x509store/StoreContext.java @@ -37,6 +37,7 @@ import java.util.Collection; import java.util.Date; import java.util.HashSet; +import java.util.LinkedList; import java.util.List; import java.util.Set; @@ -688,10 +689,8 @@ private int verifyChain() throws Exception { // We use a temporary STACK so we can chop and hack at it - List sktmp = null; - if ( untrusted != null ) { - sktmp = new ArrayList(untrusted); - } + LinkedList sktmp = untrusted != null ? new LinkedList<>(untrusted) : null; + num = chain.size(); x = chain.get(num - 1); depth = verifyParameter.depth; @@ -848,8 +847,7 @@ int build_chain() throws Exception { int trust = X509_TRUST_UNTRUSTED; int alt_untrusted = 0; int depth; - int ok = 0; - int i; + int ok; /* * Set up search policy, untrusted if possible, trusted-first if enabled. @@ -873,7 +871,7 @@ int build_chain() throws Exception { * typically the content of the peer's certificate message) so can make * multiple passes over it, while free to remove elements as we go. */ - ArrayList sktmp = untrusted != null ? new ArrayList<>(untrusted) : null; + LinkedList sktmp = untrusted != null ? new LinkedList<>(untrusted) : null; depth = verifyParameter.depth; @@ -1123,12 +1121,10 @@ int build_chain() throws Exception { private X509AuxCertificate find_issuer(List sk, X509AuxCertificate x) throws Exception { X509AuxCertificate rv = null; - for (int i = 0; i < sk.size(); i++) { - X509AuxCertificate issuer = sk.get(i); + for (X509AuxCertificate issuer : sk) { if (check_issued(x, issuer)) { rv = issuer; - if (x509_check_cert_time(ctx, rv, -1)) - break; + if (checkCertificateTime(rv)) break; } } return rv; From 99b76d86c69aa3ebc4fad88a1a358b445230045c Mon Sep 17 00:00:00 2001 From: kares Date: Wed, 6 Oct 2021 11:44:03 +0200 Subject: [PATCH 06/63] port check_trust + refactor and hide checkCertificateTime --- .../ext/openssl/x509store/StoreContext.java | 81 +++++++++++++++++-- 1 file changed, 76 insertions(+), 5 deletions(-) diff --git a/src/main/java/org/jruby/ext/openssl/x509store/StoreContext.java b/src/main/java/org/jruby/ext/openssl/x509store/StoreContext.java index 8eab997a..d6da6e7a 100644 --- a/src/main/java/org/jruby/ext/openssl/x509store/StoreContext.java +++ b/src/main/java/org/jruby/ext/openssl/x509store/StoreContext.java @@ -1496,10 +1496,81 @@ public int checkTrust() throws Exception { return verifyCallback.call(this, ZERO); } + /* + * x509_vfy.c: check_trust(X509_STORE_CTX *ctx, int num_untrusted) + */ + private int check_trust(int num_untrusted) throws Exception { + int i; + final int num = chain.size(); + int trust; + + /* + * Check trusted certificates in chain at depth num_untrusted and up. + * Note, that depths 0..num_untrusted-1 may also contain trusted + * certificates, but the caller is expected to have already checked those, + * and wants to incrementally check just any added since. + */ + for (i = num_untrusted; i < num; i++) { + X509AuxCertificate x = chain.get(i); + trust = Trust.checkTrust(x, getParam().trust, 0); + /* If explicitly trusted return trusted */ + if (trust == X509_TRUST_TRUSTED) + return X509_TRUST_TRUSTED; // goto trusted; + if (trust == X509_TRUST_REJECTED) + return check_trust_rejected(x, i); // goto rejected; + } + + /* + * If we are looking at a trusted certificate, and accept partial chains, + * the chain is PKIX trusted. + */ + if (num_untrusted < num) { + if ((getParam().flags & V_FLAG_PARTIAL_CHAIN) != 0) + return X509_TRUST_TRUSTED; // goto trusted; + return X509_TRUST_UNTRUSTED; + } + + if (num_untrusted == num && (getParam().flags & V_FLAG_PARTIAL_CHAIN) != 0) { + /* + * Last-resort call with no new trusted certificates, check the leaf + * for a direct trust store match. + */ + i = 0; + X509AuxCertificate x = chain.get(i); + X509AuxCertificate mx = lookup_cert_match(x); + if (mx == null) return X509_TRUST_UNTRUSTED; + + /* + * Check explicit auxiliary trust/reject settings. If none are set, + * we'll accept X509_TRUST_UNTRUSTED when not self-signed. + */ + trust = Trust.checkTrust(mx, getParam().trust, 0); + if (trust == X509_TRUST_REJECTED) { + return check_trust_rejected(x, i); // goto rejected; + } + + /* Replace leaf with trusted match */ + chain.set(0, mx); + this.num_untrusted = 0; + return X509_TRUST_TRUSTED; // goto trusted; + } + + /* + * If no trusted certs in chain at all return untrusted and allow + * standard (no issuer cert) etc errors to be indicated. + */ + return X509_TRUST_UNTRUSTED; + } + + private int check_trust_rejected(X509AuxCertificate x, int i) throws Exception { + if (verify_cb_cert(x, i, V_ERR_CERT_REJECTED) == 0) return X509_TRUST_REJECTED; + return X509_TRUST_UNTRUSTED; + } + /** * c: check_cert_time */ - public int checkCertificateTime(X509AuxCertificate x) throws Exception { + boolean checkCertificateTime(X509AuxCertificate x) throws Exception { final Date pTime; if ( (verifyParameter.flags & X509Utils.V_FLAG_USE_CHECK_TIME) != 0 ) { pTime = this.verifyParameter.checkTime; @@ -1511,17 +1582,17 @@ public int checkCertificateTime(X509AuxCertificate x) throws Exception { error = X509Utils.V_ERR_CERT_NOT_YET_VALID; currentCertificate = x; if ( verifyCallback.call(this, ZERO) == 0 ) { - return 0; + return false; } } if ( ! x.getNotAfter().after(pTime) ) { error = X509Utils.V_ERR_CERT_HAS_EXPIRED; currentCertificate = x; if ( verifyCallback.call(this, ZERO) == 0 ) { - return 0; + return false; } } - return 1; + return true; } /** @@ -1721,7 +1792,7 @@ public int call(final StoreContext context) throws Exception { } xs.setValid(true); - ok = context.checkCertificateTime(xs); + ok = context.checkCertificateTime(xs) ? 1 : 0; if ( ok == 0 ) return ok; context.currentIssuer = xi; From 550eb192ce9f3e214748f81ceb8210418754b412 Mon Sep 17 00:00:00 2001 From: kares Date: Tue, 12 Oct 2021 16:32:21 +0200 Subject: [PATCH 07/63] more upstream sync with C OpenSSL 1.1.1 --- .../ext/openssl/x509store/StoreContext.java | 193 +++++++++++------- .../openssl/x509store/X509AuxCertificate.java | 12 +- .../ext/openssl/x509store/X509Utils.java | 20 +- 3 files changed, 135 insertions(+), 90 deletions(-) diff --git a/src/main/java/org/jruby/ext/openssl/x509store/StoreContext.java b/src/main/java/org/jruby/ext/openssl/x509store/StoreContext.java index d6da6e7a..99e0cd46 100644 --- a/src/main/java/org/jruby/ext/openssl/x509store/StoreContext.java +++ b/src/main/java/org/jruby/ext/openssl/x509store/StoreContext.java @@ -1124,7 +1124,7 @@ private X509AuxCertificate find_issuer(List sk, X509AuxCerti for (X509AuxCertificate issuer : sk) { if (check_issued(x, issuer)) { rv = issuer; - if (checkCertificateTime(rv)) break; + if (x509_check_cert_time(rv, -1)) break; } } return rv; @@ -1350,7 +1350,7 @@ private int check_purpose(X509AuxCertificate x, int purpose, int depth, byte mus * static int check_chain_extensions(X509_STORE_CTX *ctx) */ private int check_chain_extensions() throws Exception { - byte must_be_ca, int plen = 0; + byte must_be_ca; int plen = 0; X509AuxCertificate x; int proxy_path_length = 0; int purpose; @@ -1567,31 +1567,41 @@ private int check_trust_rejected(X509AuxCertificate x, int i) throws Exception { return X509_TRUST_UNTRUSTED; } - /** - * c: check_cert_time + /*- + * Check certificate validity times. + * If depth >= 0, invoke verification callbacks on error, otherwise just return + * the validation status. + * + * Return 1 on success, 0 otherwise. */ - boolean checkCertificateTime(X509AuxCertificate x) throws Exception { + boolean x509_check_cert_time(X509AuxCertificate x, final int depth) throws Exception { final Date pTime; - if ( (verifyParameter.flags & X509Utils.V_FLAG_USE_CHECK_TIME) != 0 ) { - pTime = this.verifyParameter.checkTime; + if ((getParam().flags & V_FLAG_USE_CHECK_TIME) != 0) { + pTime = getParam().checkTime; + } else if ((getParam().flags & V_FLAG_NO_CHECK_TIME) != 0) { + return true; } else { pTime = Calendar.getInstance().getTime(); } - if ( ! x.getNotBefore().before(pTime) ) { - error = X509Utils.V_ERR_CERT_NOT_YET_VALID; - currentCertificate = x; - if ( verifyCallback.call(this, ZERO) == 0 ) { - return false; - } + int i = x.getNotBefore().compareTo(pTime); + if (i >= 0 && depth < 0) return false; + if (i == 0 && verify_cb_cert(x, depth, V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD) == 0) { + return false; } - if ( ! x.getNotAfter().after(pTime) ) { - error = X509Utils.V_ERR_CERT_HAS_EXPIRED; - currentCertificate = x; - if ( verifyCallback.call(this, ZERO) == 0 ) { - return false; - } + if (i > 0 && verify_cb_cert(x, depth, V_ERR_CERT_NOT_YET_VALID) == 0) { + return false; } + + i = x.getNotAfter().compareTo(pTime); + if (i >= 0 && depth < 0) return false; + if (i == 0 && verify_cb_cert(x, depth, V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD) == 0) { + return false; + } + if (i < 0 && verify_cb_cert(x, depth, V_ERR_CERT_HAS_EXPIRED) == 0) { + return false; + } + return true; } @@ -1629,8 +1639,8 @@ public int checkCertificate() throws Exception { public int checkCRLTime(X509CRL crl, int notify) throws Exception { currentCRL = crl; final Date pTime; - if ( (verifyParameter.flags & X509Utils.V_FLAG_USE_CHECK_TIME) != 0 ) { - pTime = this.verifyParameter.checkTime; + if ((getParam().flags & V_FLAG_USE_CHECK_TIME) != 0) { + pTime = getParam().checkTime; } else { pTime = Calendar.getInstance().getTime(); } @@ -1739,75 +1749,108 @@ public int call(StoreContext context, Integer outcome) { } }; - /** - * c: internal_verify + /* + * c: static int internal_verify(X509_STORE_CTX *ctx) */ final static Store.VerifyFunction internalVerify = new Store.VerifyFunction() { - public int call(final StoreContext context) throws Exception { - Store.VerifyCallbackFunction verifyCallback = context.verifyCallback; - - int n = context.chain.size(); - context.errorDepth = n - 1; - n--; - X509AuxCertificate xi = context.chain.get(n); - X509AuxCertificate xs = null; - int ok; + public int call(final StoreContext ctx) throws Exception { + int n = ctx.chain.size() - 1; + X509AuxCertificate xi = ctx.chain.get(n); + X509AuxCertificate xs; - if ( context.checkIssued.call(context,xi,xi) != 0 ) { + if (ctx.checkIssued.call(ctx, xi, xi) != 0) { xs = xi; - } - else { - if ( n <= 0 ) { - context.error = X509Utils.V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE; - context.currentCertificate = xi; - ok = verifyCallback.call(context, ZERO); - return ok; + } else { + if ((ctx.getParam().flags & V_FLAG_PARTIAL_CHAIN) != 0) { + xs = xi; + // goto check_cert; + if (!check_cert(ctx, xi, xs, n)) { + return 0; + } + if (--n >= 0) { + xi = xs; + // xs = ctx.chain.get(n); + } + // goto end } - else { - n--; - context.errorDepth = n; - xs = context.chain.get(n); + if (n <= 0) { + return ctx.verify_cb_cert(xi, 0, V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE); } + + n--; + ctx.errorDepth = n; + xs = ctx.chain.get(n); } + /* + * Do not clear ctx->error=0, it must be "sticky", only the user's callback + * is allowed to reset errors (at its own peril). + */ while ( n >= 0 ) { - context.errorDepth = n; - if ( ! xs.isValid() ) { - try { - xs.verify(xi.getPublicKey()); - } - catch(Exception e) { - /* - System.err.println("n: " + n); - System.err.println("verifying: " + xs); - System.err.println("verifying with issuer?: " + xi); - System.err.println("verifying with issuer.key?: " + xi.getPublicKey()); - System.err.println("exception: " + e); - */ - context.error = X509Utils.V_ERR_CERT_SIGNATURE_FAILURE; - context.currentCertificate = xs; - ok = verifyCallback.call(context, ZERO); - if ( ok == 0 ) return ok; + /* + * Skip signature check for self signed certificates unless explicitly + * asked for. It doesn't add any security and just wastes time. If + * the issuer's public key is unusable, report the issuer certificate + * and its depth (rather than the depth of the subject). + */ + if (xs != xi || (ctx.getParam().flags & V_FLAG_CHECK_SS_SIGNATURE) != 0) { + PublicKey pkey = xi.getPublicKey(); + if (pkey == null) { + if (ctx.verify_cb_cert(xi, xi != xs ? n+1 : n, V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY) == 0) + return 0; + } else if (!X509_verify(xs, pkey)) { + if (ctx.verify_cb_cert(xs, n, V_ERR_CERT_SIGNATURE_FAILURE) == 0) + return 0; } } - xs.setValid(true); - ok = context.checkCertificateTime(xs) ? 1 : 0; - if ( ok == 0 ) return ok; - - context.currentIssuer = xi; - context.currentCertificate = xs; - ok = verifyCallback.call(context, Integer.valueOf(1)); - if ( ok == 0 ) return ok; - - n--; - if ( n >= 0 ) { + // check_cert : + if (!check_cert(ctx, xi, xs, n)) { + return 0; + } + if (--n >= 0) { xi = xs; - xs = context.chain.get(n); + xs = ctx.chain.get(n); } + // end } - ok = 1; - return ok; + return 1; + } + + // goto check_cert: + private boolean check_cert(final StoreContext ctx, X509AuxCertificate xi, X509AuxCertificate xs, int n) + throws Exception { + /* Calls verify callback as needed */ + if (!ctx.x509_check_cert_time(xs, n)) + return false; + + /* + * Signal success at this depth. However, the previous error (if any) + * is retained. + */ + ctx.currentIssuer = xi; + ctx.currentCertificate = xs; + ctx.errorDepth = n; + if (ctx.verifyCallback.call(ctx, 1) == 0) + return false; + + return true; // do not halt yet but : + //if (--n >= 0) { + // xi = xs; + // xs = ctx.chain.get(n); + //} + } + + private boolean X509_verify(X509AuxCertificate xs, PublicKey pkey) { + if (xs.verified) return true; + + try { + xs.verify(pkey); + } + catch (Exception e) { + return false; + } + return xs.verified = true; } }; diff --git a/src/main/java/org/jruby/ext/openssl/x509store/X509AuxCertificate.java b/src/main/java/org/jruby/ext/openssl/x509store/X509AuxCertificate.java index 4e6713b8..184d06ba 100644 --- a/src/main/java/org/jruby/ext/openssl/x509store/X509AuxCertificate.java +++ b/src/main/java/org/jruby/ext/openssl/x509store/X509AuxCertificate.java @@ -73,7 +73,7 @@ public class X509AuxCertificate extends X509Certificate implements Cloneable { final X509Aux aux; - private boolean valid = false; + boolean verified = false; // opt: avoids doing internal_verify twice private int ex_flags = 0; public X509AuxCertificate(Certificate wrap) throws IOException, CertificateException { @@ -105,19 +105,11 @@ public final X509AuxCertificate clone() { final X509AuxCertificate cloneForCache() { final X509AuxCertificate clone = clone(); - clone.valid = false; + clone.verified = false; clone.ex_flags = 0; return clone; } - public boolean isValid() { - return valid; - } - - public void setValid(boolean v) { - this.valid = v; - } - public int getExFlags() { return ex_flags; } diff --git a/src/main/java/org/jruby/ext/openssl/x509store/X509Utils.java b/src/main/java/org/jruby/ext/openssl/x509store/X509Utils.java index e9a4252e..5424f979 100644 --- a/src/main/java/org/jruby/ext/openssl/x509store/X509Utils.java +++ b/src/main/java/org/jruby/ext/openssl/x509store/X509Utils.java @@ -446,7 +446,7 @@ else if (maybeCertFile != null && new File(maybeCertFile).exists()) { /* Delta CRL support */ //public static final int V_FLAG_USE_DELTAS = 0x2000; /* Check self-signed CA signature */ - //public static final int V_FLAG_CHECK_SS_SIGNATURE = 0x4000; + public static final int V_FLAG_CHECK_SS_SIGNATURE = 0x4000; /* Use trusted store first */ public static final int V_FLAG_TRUSTED_FIRST = 0x8000; @@ -460,6 +460,8 @@ else if (maybeCertFile != null && new File(maybeCertFile).exists()) { * will force the behaviour to match that of previous versions. */ public static final int V_FLAG_NO_ALT_CHAINS = 0x100000; + /* Do not check certificate/CRL validity against current time */ + public static final int V_FLAG_NO_CHECK_TIME = 0x200000; /* Internal use: mask of policy related options */ @@ -525,12 +527,20 @@ else if (maybeCertFile != null && new File(maybeCertFile).exists()) { public static final int X509_TRUST_OBJECT_SIGN = 5; public static final int X509_TRUST_OCSP_SIGN = 6; public static final int X509_TRUST_OCSP_REQUEST = 7; + public static final int X509_TRUST_TSA = 8; public static final int X509_TRUST_MIN = 1; - public static final int X509_TRUST_MAX = 7; - - public static final int X509_TRUST_DYNAMIC = 1; - public static final int X509_TRUST_DYNAMIC_NAME = 2; + public static final int X509_TRUST_MAX = 8; + + /* trust_flags values */ + public static final int X509_TRUST_DYNAMIC = (1 << 0); + public static final int X509_TRUST_DYNAMIC_NAME = (1 << 1); + /* No compat trust if self-signed, preempts "DO_SS" */ + public static final int X509_TRUST_NO_SS_COMPAT = (1 << 2); + /* Compat trust if no explicit accepted trust EKUs */ + public static final int X509_TRUST_DO_SS_COMPAT = (1 << 3); + /* Accept "anyEKU" as a wildcard rejection OID and as a wildcard trust OID */ + public static final int X509_TRUST_OK_ANY_EKU = (1 << 4); public static final int X509_TRUST_TRUSTED = 1; public static final int X509_TRUST_REJECTED = 2; From b46084062855b4447fa6b4091d8007c59581deb7 Mon Sep 17 00:00:00 2001 From: kares Date: Tue, 12 Oct 2021 17:49:27 +0200 Subject: [PATCH 08/63] [refactor] align X509_STORE_CTX_get_by_subject --- .../ext/openssl/x509store/StoreContext.java | 28 ++++++------------- 1 file changed, 9 insertions(+), 19 deletions(-) diff --git a/src/main/java/org/jruby/ext/openssl/x509store/StoreContext.java b/src/main/java/org/jruby/ext/openssl/x509store/StoreContext.java index 99e0cd46..12bbb50a 100644 --- a/src/main/java/org/jruby/ext/openssl/x509store/StoreContext.java +++ b/src/main/java/org/jruby/ext/openssl/x509store/StoreContext.java @@ -60,8 +60,6 @@ public class StoreContext { private final Store store; - private int currentMethod; - X509AuxCertificate certificate; List untrusted; List crls; @@ -208,7 +206,6 @@ public static X509AuxCertificate ensureAux(final X509Certificate input) { */ public int init(X509AuxCertificate cert, List chain) { int ret = 1; - this.currentMethod = 0; this.certificate = cert; this.untrusted = chain; this.crls = null; @@ -605,31 +602,24 @@ public int setDefault(String name) { return verifyParameter.inherit(p); } - /** - * c: X509_STORE_get_by_subject (it gets X509_STORE_CTX as the first parameter) + /* + * int X509_STORE_CTX_get_by_subject(X509_STORE_CTX *vs, X509_LOOKUP_TYPE type, + * X509_NAME *name, X509_OBJECT *ret) */ public int getBySubject(int type, Name name, X509Object[] ret) throws Exception { - Store c = store; + final Store store = this.store; - X509Object tmp = X509Object.retrieveBySubject(c.getObjects(),type,name); - if ( tmp == null ) { - List certificateMethods = c.getCertificateMethods(); - for(int i=currentMethod; i 0 ) { + if (j != 0) { tmp = stmp[0]; break; } } - currentMethod = 0; - - if ( tmp == null ) return 0; + if (tmp == null) return 0; } ret[0] = tmp; return 1; From 19a65626ed3f98e217c02829372922c02b18fb9e Mon Sep 17 00:00:00 2001 From: kares Date: Tue, 12 Oct 2021 17:50:18 +0200 Subject: [PATCH 09/63] review (the public) X509_verify_cert --- .../ext/openssl/x509store/StoreContext.java | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/src/main/java/org/jruby/ext/openssl/x509store/StoreContext.java b/src/main/java/org/jruby/ext/openssl/x509store/StoreContext.java index 12bbb50a..0c61bf30 100644 --- a/src/main/java/org/jruby/ext/openssl/x509store/StoreContext.java +++ b/src/main/java/org/jruby/ext/openssl/x509store/StoreContext.java @@ -627,20 +627,22 @@ public int getBySubject(int type, Name name, X509Object[] ret) throws Exception /** * c: X509_verify_cert + /* + * c: int X509_verify_cert(X509_STORE_CTX *ctx) */ public int verifyCertificate() throws Exception { - if ( certificate == null ) { + if (certificate == null) { addError(X509_R_NO_CERT_SET_FOR_US_TO_VERIFY); - this.error = X509Utils.V_ERR_INVALID_CALL; + this.error = V_ERR_INVALID_CALL; return -1; } - if ( chain != null ) { + if (chain != null) { /* * This X509_STORE_CTX has already been used to verify a cert. We cannot do another one. */ addError(ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); - this.error = X509Utils.V_ERR_INVALID_CALL; + this.error = V_ERR_INVALID_CALL; return -1; } @@ -648,13 +650,13 @@ public int verifyCertificate() throws Exception { * first we make sure the chain we are going to build is present and that * the first entry is in place */ - if ( chain == null ) { + //if (chain == null) { chain = new ArrayList(8); chain.add(certificate); - lastUntrusted = 1; - } + num_untrusted = 1; + //} - // TODO not implemented: + // NOTE: NOT IMPLEMENTED /* If the peer's public key is too weak, we can stop early. */ int ret = verifyChain(); From fe5568c1ebf8e60929fbefd73e9337664a728464 Mon Sep 17 00:00:00 2001 From: kares Date: Tue, 12 Oct 2021 17:57:11 +0200 Subject: [PATCH 10/63] [refactor] re-use field for untrusted count --- .../ext/openssl/x509store/StoreContext.java | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/src/main/java/org/jruby/ext/openssl/x509store/StoreContext.java b/src/main/java/org/jruby/ext/openssl/x509store/StoreContext.java index 0c61bf30..8118cbc5 100644 --- a/src/main/java/org/jruby/ext/openssl/x509store/StoreContext.java +++ b/src/main/java/org/jruby/ext/openssl/x509store/StoreContext.java @@ -86,10 +86,8 @@ interface CheckPolicyFunction extends Function1 {} Store.CleanupFunction cleanup; public boolean isValid; - public int lastUntrusted; - - private int num_untrusted; + private int num_untrusted; // lastUntrusted in the chain private ArrayList chain; private PolicyTree tree; @@ -209,7 +207,7 @@ public int init(X509AuxCertificate cert, List chain) { this.certificate = cert; this.untrusted = chain; this.crls = null; - this.lastUntrusted = 0; + this.num_untrusted = 0; this.otherContext = null; this.isValid = false; this.chain = null; @@ -696,7 +694,7 @@ private int verifyChain() throws Exception { if ( xtmp != null ) { chain.add(xtmp); sktmp.remove(xtmp); - lastUntrusted++; + num_untrusted++; x = xtmp; num++; continue; @@ -735,12 +733,12 @@ private int verifyChain() throws Exception { // so we get any trust settings. x = xtmp; chain.set(i-1,x); - lastUntrusted = 0; + num_untrusted = 0; } } else { // extract and save self signed certificate for later use chain_ss = chain.remove(chain.size()-1); - lastUntrusted--; + num_untrusted--; num--; x = chain.get(num-1); } @@ -771,7 +769,7 @@ private int verifyChain() throws Exception { /* Is last certificate looked up self signed? */ if ( checkIssued.call(this, x, x) == 0 ) { if ( chain_ss == null || checkIssued.call(this, x, chain_ss) == 0 ) { - if (lastUntrusted >= num) { + if (num_untrusted >= num) { error = X509Utils.V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY; } else { error = X509Utils.V_ERR_UNABLE_TO_GET_ISSUER_CERT; @@ -780,7 +778,7 @@ private int verifyChain() throws Exception { } else { chain.add(chain_ss); num++; - lastUntrusted = num; + num_untrusted = num; currentCertificate = chain_ss; error = X509Utils.V_ERR_SELF_SIGNED_CERT_IN_CHAIN; } @@ -1191,7 +1189,7 @@ public int checkChainExtensions() throws Exception { } catch (SecurityException e) { /* ignore if we can't use System.getenv */ } - for ( int i = 0; i < lastUntrusted; i++ ) { + for ( int i = 0; i < num_untrusted; i++ ) { // lastUntrusted int ret; x = chain.get(i); if ( (verifyParameter.flags & X509Utils.V_FLAG_IGNORE_CRITICAL) == 0 && unhandledCritical(x) ) { From 45185c8e122870e8d7993b7d2b51f7a8133b0820 Mon Sep 17 00:00:00 2001 From: kares Date: Tue, 12 Oct 2021 18:01:15 +0200 Subject: [PATCH 11/63] [refactor] a no-op --- .../java/org/jruby/ext/openssl/x509store/StoreContext.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/jruby/ext/openssl/x509store/StoreContext.java b/src/main/java/org/jruby/ext/openssl/x509store/StoreContext.java index 8118cbc5..94f4c782 100644 --- a/src/main/java/org/jruby/ext/openssl/x509store/StoreContext.java +++ b/src/main/java/org/jruby/ext/openssl/x509store/StoreContext.java @@ -90,9 +90,9 @@ interface CheckPolicyFunction extends Function1 {} private int num_untrusted; // lastUntrusted in the chain private ArrayList chain; - private PolicyTree tree; - public int explicitPolicy; + private PolicyTree tree; + private int explicitPolicy; public int error; public int errorDepth; From 7bd25790ae75a2c9037cab66e6520f1a46fe164a Mon Sep 17 00:00:00 2001 From: kares Date: Tue, 12 Oct 2021 18:02:23 +0200 Subject: [PATCH 12/63] prepare for ctx->parent + align check_revocation --- .../ext/openssl/x509store/StoreContext.java | 54 ++++++++++--------- 1 file changed, 30 insertions(+), 24 deletions(-) diff --git a/src/main/java/org/jruby/ext/openssl/x509store/StoreContext.java b/src/main/java/org/jruby/ext/openssl/x509store/StoreContext.java index 94f4c782..7bb336e9 100644 --- a/src/main/java/org/jruby/ext/openssl/x509store/StoreContext.java +++ b/src/main/java/org/jruby/ext/openssl/x509store/StoreContext.java @@ -103,6 +103,8 @@ interface CheckPolicyFunction extends Function1 {} List extraData; + private StoreContext parent; // NOTE: not implemented - dummy null for now + public Store getStore() { return store; } @@ -1359,13 +1361,13 @@ private int check_chain_extensions() throws Exception { must_be_ca = -1; /* CRL path validation */ - //if (ctx->parent) { // todo this.parent not implemented - // allow_proxy_certs = 0; - // purpose = X509_PURPOSE_CRL_SIGN; - //} else { + if (parent != null) { // NOT IMPLEMENTED: always null + allow_proxy_certs = false; + purpose = X509_PURPOSE_CRL_SIGN; + } else { allow_proxy_certs = (getParam().flags & V_FLAG_ALLOW_PROXY_CERTS) != 0; purpose = getParam().purpose; - //} + } for (int i = 0; i < num; i++) { int ret; @@ -1844,28 +1846,32 @@ private boolean X509_verify(X509AuxCertificate xs, PublicKey pkey) { } }; - /** - * c: check_revocation + /* + * c: static int check_revocation(X509_STORE_CTX *ctx) */ + private int check_revocation() throws Exception { + if ( (getParam().flags & V_FLAG_CRL_CHECK) == 0 ) { + return 1; + } + final int last; + if ( (getParam().flags & V_FLAG_CRL_CHECK_ALL) != 0 ) { + last = chain.size() - 1; + } else { + /* If checking CRL paths this isn't the EE certificate */ + if (parent != null) return 1; // NOT IMPLEMENTED: always null + last = 0; + } + for ( int i=0; i<=last; i++ ) { + errorDepth = i; + int ok = checkCertificate(); // check_cert(ctx); + if (ok == 0) return 0; + } + return 1; + } + final static Store.CheckRevocationFunction defaultCheckRevocation = new Store.CheckRevocationFunction() { public int call(final StoreContext context) throws Exception { - if ( (context.verifyParameter.flags & X509Utils.V_FLAG_CRL_CHECK) == 0 ) { - return 1; - } - final int last; - if ( (context.verifyParameter.flags & X509Utils.V_FLAG_CRL_CHECK_ALL) != 0 ) { - last = context.chain.size() - 1; - } - else { - last = 0; - } - int ok; - for ( int i=0; i<=last; i++ ) { - context.errorDepth = i; - ok = context.checkCertificate(); - if ( ok == 0 ) return 0; - } - return 1; + return context.check_revocation(); } }; From 64f20072fc0592e1a727d1f8fa9aabeb45974e0b Mon Sep 17 00:00:00 2001 From: kares Date: Tue, 12 Oct 2021 18:03:15 +0200 Subject: [PATCH 13/63] ported OpenSSL 1.1.1 verify_chain logic --- .../ext/openssl/x509store/StoreContext.java | 41 +++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/src/main/java/org/jruby/ext/openssl/x509store/StoreContext.java b/src/main/java/org/jruby/ext/openssl/x509store/StoreContext.java index 7bb336e9..16ae9399 100644 --- a/src/main/java/org/jruby/ext/openssl/x509store/StoreContext.java +++ b/src/main/java/org/jruby/ext/openssl/x509store/StoreContext.java @@ -822,6 +822,47 @@ private int verifyChain() throws Exception { return ok; } + /* + @ @note: based OpenSSL 1.1.1 + * + * c: static int verify_chain(X509_STORE_CTX *ctx) + */ + int verify_chain() throws Exception { + int err; + int ok; + + /* + * Before either returning with an error, or continuing with CRL checks, + * instantiate chain public key parameters. + */ + if ((ok = build_chain()) == 0 || + (ok = check_chain_extensions()) == 0 // || + //(ok = check_auth_level(ctx)) == 0 || + //(ok = check_id()) == 0 || 1) + ); + if (ok == 0 || (ok = check_revocation()) == 0) + return ok; + + //err = X509_chain_check_suiteb(&ctx->error_depth, NULL, ctx->chain, ctx->param->flags); + //if (err != V_OK) { + // if ((ok = verify_cb_cert(null, this.errorDepth, err)) == 0) + // return ok; + //} + + /* Verify chain signatures and expiration times */ + ok = verify != null ? verify.call(this) : internalVerify.call(this); + if (ok == 0) return ok; + + //if ((ok = check_name_constraints(ctx)) == 0) + // return ok; + + /* If we get this far evaluate policies */ + if ((getParam().flags & V_FLAG_POLICY_CHECK) != 0) { + ok = check_policy(); + } + return ok; + } + private static final short S_DOUNTRUSTED = (1 << 0); /* Search untrusted chain */ private static final short S_DOTRUSTED = (1 << 1); /* Search trusted store */ private static final short S_DOALTERNATE = (1 << 2); /* Retry with pruned alternate chain */ From c18704eb9e7d40528e5388bbcba5613e998bd7f9 Mon Sep 17 00:00:00 2001 From: kares Date: Tue, 12 Oct 2021 18:03:51 +0200 Subject: [PATCH 14/63] [refactor] extract dummy policy check --- .../org/jruby/ext/openssl/x509store/StoreContext.java | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/jruby/ext/openssl/x509store/StoreContext.java b/src/main/java/org/jruby/ext/openssl/x509store/StoreContext.java index 16ae9399..9e92ba35 100644 --- a/src/main/java/org/jruby/ext/openssl/x509store/StoreContext.java +++ b/src/main/java/org/jruby/ext/openssl/x509store/StoreContext.java @@ -2018,12 +2018,20 @@ public int call(final StoreContext context, final X509CRL crl, X509AuxCertificat } }; + /* + * c: static int check_policy(X509_STORE_CTX *ctx) + */ + private int check_policy() throws Exception { + // NOTE: NOT IMPLEMENTED + return 1; + } + /** * c: check_policy */ final static CheckPolicyFunction defaultCheckPolicy = new CheckPolicyFunction() { public int call(StoreContext context) throws Exception { - return 1; + return context.check_policy(); } }; }// X509_STORE_CTX From 1988f7f882a7d4221e5ac0f9d1d76f19c4d05099 Mon Sep 17 00:00:00 2001 From: kares Date: Tue, 12 Oct 2021 18:05:13 +0200 Subject: [PATCH 15/63] port lookup_cert_match w X509_STORE_CTX_get1_certs (DRAFT) --- .../ext/openssl/x509store/StoreContext.java | 81 ++++++++++++++++++- 1 file changed, 79 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/jruby/ext/openssl/x509store/StoreContext.java b/src/main/java/org/jruby/ext/openssl/x509store/StoreContext.java index 9e92ba35..c65b0738 100644 --- a/src/main/java/org/jruby/ext/openssl/x509store/StoreContext.java +++ b/src/main/java/org/jruby/ext/openssl/x509store/StoreContext.java @@ -625,8 +625,67 @@ public int getBySubject(int type, Name name, X509Object[] ret) throws Exception return 1; } - /** - * c: X509_verify_cert + /* + * STACK_OF(X509) *X509_STORE_CTX_get1_certs(X509_STORE_CTX *ctx, X509_NAME *nm) + */ + List X509_STORE_CTX_get1_certs(final Name nm) { + if (store == null) return null; + +// X509_STORE_lock(store); +// idx = x509_object_idx_cnt(store->objs, X509_LU_X509, nm, &cnt); +// if (idx < 0) { +// /* +// * Nothing found in cache: do lookup to possibly add new objects to +// * cache +// */ +// X509_OBJECT *xobj = X509_OBJECT_new(); +// +// X509_STORE_unlock(store); +// +// if (xobj == NULL) +// return NULL; +// if (!X509_STORE_CTX_get_by_subject(ctx, X509_LU_X509, nm, xobj)) { +// X509_OBJECT_free(xobj); +// return NULL; +// } +// X509_OBJECT_free(xobj); +// X509_STORE_lock(store); +// idx = x509_object_idx_cnt(store->objs, X509_LU_X509, nm, &cnt); +// if (idx < 0) { +// X509_STORE_unlock(store); +// return NULL; +// } +// } + +// sk = sk_X509_new_null(); +// for (i = 0; i < cnt; i++, idx++) { +// obj = sk_X509_OBJECT_value(store->objs, idx); +// x = obj->data.x509; +// if (!X509_up_ref(x)) { +// X509_STORE_unlock(store); +// sk_X509_pop_free(sk, X509_free); +// return NULL; +// } +// if (!sk_X509_push(sk, x)) { +// X509_STORE_unlock(store); +// X509_free(x); +// sk_X509_pop_free(sk, X509_free); +// return NULL; +// } +// } +// X509_STORE_unlock(store); +// return sk; + + ArrayList sk = new ArrayList(); + for (X509Object obj : store.getObjects()) { + if (obj.type() == X509_LU_X509 && obj.isName(nm)) { + sk.add(((Certificate) obj).cert); + } + } + + return sk; + } + /* * c: int X509_verify_cert(X509_STORE_CTX *ctx) */ @@ -1718,6 +1777,24 @@ public int getCRLStack(X509CRL[] pcrl, Name name, List crls) throws Exc return 0; } + /* Given a certificate try and find an exact match in the store */ + + private X509AuxCertificate lookup_cert_match(X509AuxCertificate x) { + /* Lookup all certs with matching subject name */ + List certs = lookup_certs(new Name(x.getSubjectX500Principal())); + if (certs == null) return null; + /* Look for exact match */ + for (X509AuxCertificate xtmp : certs) { + if (xtmp.equals(x)) // !X509_cmp(xtmp, x) + break; + } + return null; // xtmp = null + } + + private List lookup_certs(final Name name) { + return X509_STORE_CTX_get1_certs(name); + } + /* * Inform the verify callback of an error. * If B is not NULL it is the error cert, otherwise use the chain cert at From caf7d07fd4a59b17348e55a7149b5f5b4fa0ac5f Mon Sep 17 00:00:00 2001 From: kares Date: Wed, 13 Oct 2021 14:30:12 +0200 Subject: [PATCH 16/63] [refactor] and move around duplicate helpers deprecated ones are for the current (legacy) verify_chain --- .../ext/openssl/x509store/StoreContext.java | 27 +++++++++---------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/src/main/java/org/jruby/ext/openssl/x509store/StoreContext.java b/src/main/java/org/jruby/ext/openssl/x509store/StoreContext.java index c65b0738..869c96de 100644 --- a/src/main/java/org/jruby/ext/openssl/x509store/StoreContext.java +++ b/src/main/java/org/jruby/ext/openssl/x509store/StoreContext.java @@ -307,18 +307,6 @@ public void cleanup() throws Exception { extraData = null; } - /** - * c: find_issuer - */ - public X509AuxCertificate findIssuer(final List certs, final X509AuxCertificate cert) throws Exception { - for ( X509AuxCertificate issuer : certs ) { - if ( checkIssued.call(this, cert, issuer) != 0 ) { - return issuer; - } - } - return null; - } - public List getExtraData() { if ( this.extraData != null ) return this.extraData; ArrayList extraData = new ArrayList(8); @@ -965,7 +953,7 @@ int build_chain() throws Exception { */ LinkedList sktmp = untrusted != null ? new LinkedList<>(untrusted) : null; - depth = verifyParameter.depth; + depth = getParam().depth; /* * Still absurdly large, but arithmetically safe, a lower hard upper bound @@ -1205,6 +1193,16 @@ int build_chain() throws Exception { } } + @Deprecated // legacy find_issuer + public X509AuxCertificate findIssuer(final List certs, final X509AuxCertificate cert) throws Exception { + for ( X509AuxCertificate issuer : certs ) { + if ( checkIssued.call(this, cert, issuer) != 0 ) { + return issuer; + } + } + return null; + } + /* * Given a STACK_OF(X509) find the issuer of cert (if any) * @@ -1569,7 +1567,8 @@ private boolean isSelfIssued(final X509AuxCertificate x) throws Exception { return checkIssued.call(this, x, x) != 0; // TODO self-signed == self-issued? } - public int checkTrust() throws Exception { + @Deprecated // legacy check_trust + private int checkTrust() throws Exception { int i,ok; X509AuxCertificate x; i = chain.size()-1; From 18eb94ab4d15ab370ae4cafb4e14c9289dbc5a50 Mon Sep 17 00:00:00 2001 From: kares Date: Wed, 13 Oct 2021 14:30:59 +0200 Subject: [PATCH 17/63] TEMP: verify chain switch w a -Dverify_legacy --- .../ext/openssl/x509store/StoreContext.java | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/src/main/java/org/jruby/ext/openssl/x509store/StoreContext.java b/src/main/java/org/jruby/ext/openssl/x509store/StoreContext.java index 869c96de..8ae3119f 100644 --- a/src/main/java/org/jruby/ext/openssl/x509store/StoreContext.java +++ b/src/main/java/org/jruby/ext/openssl/x509store/StoreContext.java @@ -719,10 +719,20 @@ public int verifyCertificate() throws Exception { return ret; } - /** - * c: verify_chain - */ + private static final boolean VERIFY_LEGACY = Boolean.getBoolean("verify_legacy"); + private int verifyChain() throws Exception { + if (VERIFY_LEGACY) return verify_chain_legacy(); + return verify_chain(); + } + + /* + @ @note: based on pre OpenSSL 1.0 code + * + * c: static int verify_chain(X509_STORE_CTX *ctx) + */ + @SuppressWarnings("deprecation") + int verify_chain_legacy() throws Exception { X509AuxCertificate x, xtmp = null, chain_ss = null; int bad_chain = 0, depth, i, num; From b985c84371a005215714563c3d3bcb19d2879fdc Mon Sep 17 00:00:00 2001 From: kares Date: Wed, 13 Oct 2021 18:00:41 +0200 Subject: [PATCH 18/63] [refactor] simplify - get rid of extra checks --- .../jruby/ext/openssl/x509store/Function1.java | 6 ------ .../org/jruby/ext/openssl/x509store/Lookup.java | 8 ++++---- .../org/jruby/ext/openssl/x509store/Store.java | 15 +++------------ .../jruby/ext/openssl/x509store/StoreContext.java | 4 ++-- 4 files changed, 9 insertions(+), 24 deletions(-) diff --git a/src/main/java/org/jruby/ext/openssl/x509store/Function1.java b/src/main/java/org/jruby/ext/openssl/x509store/Function1.java index 2d1d4f63..9785ca77 100644 --- a/src/main/java/org/jruby/ext/openssl/x509store/Function1.java +++ b/src/main/java/org/jruby/ext/openssl/x509store/Function1.java @@ -33,11 +33,5 @@ * @author Ola Bini */ interface Function1 { - static class Empty implements Function1 { - public int call(Object arg0) { - return -1; - } - } - public static final Function1.Empty EMPTY = new Empty(); int call(T arg0) throws Exception; }// Function1 diff --git a/src/main/java/org/jruby/ext/openssl/x509store/Lookup.java b/src/main/java/org/jruby/ext/openssl/x509store/Lookup.java index efe09cb1..023fe756 100644 --- a/src/main/java/org/jruby/ext/openssl/x509store/Lookup.java +++ b/src/main/java/org/jruby/ext/openssl/x509store/Lookup.java @@ -81,7 +81,7 @@ public Lookup(Ruby runtime, LookupMethod method) { this.runtime = runtime; final LookupMethod.NewItemFunction newItem = method.newItem; - if ( newItem != null && newItem != Function1.EMPTY ) { + if ( newItem != null ) { final int result; try { result = newItem.call(this); @@ -364,7 +364,7 @@ private String envEntry(final String key) { * c: X509_LOOKUP_free */ public void free() throws Exception { - if ( method != null && method.free != null && method.free != Function1.EMPTY ) { + if ( method != null && method.free != null ) { method.free.call(this); } } @@ -374,7 +374,7 @@ public void free() throws Exception { */ public int init() throws Exception { if ( method == null ) return 0; - if ( method.init != null && method.init != Function1.EMPTY ) { + if ( method.init != null ) { return method.init.call(this); } return 1; @@ -427,7 +427,7 @@ public int byAlias(final int type, final String alias, final X509Object[] ret) t public int shutdown() throws Exception { if ( method == null ) return 0; - if ( method.shutdown != null && method.shutdown != Function1.EMPTY ) { + if ( method.shutdown != null ) { return method.shutdown.call(this); } return 1; diff --git a/src/main/java/org/jruby/ext/openssl/x509store/Store.java b/src/main/java/org/jruby/ext/openssl/x509store/Store.java index fd989494..ce4c200a 100644 --- a/src/main/java/org/jruby/ext/openssl/x509store/Store.java +++ b/src/main/java/org/jruby/ext/openssl/x509store/Store.java @@ -51,13 +51,8 @@ */ public class Store implements X509TrustManager { - public static interface VerifyFunction extends Function1 { - public static final VerifyFunction EMPTY = new VerifyFunction(){ - public int call(StoreContext context) { - return -1; - } - }; - } + public interface VerifyFunction extends Function1 { } + public static interface VerifyCallbackFunction extends Function2 { public static final VerifyCallbackFunction EMPTY = new VerifyCallbackFunction(){ public int call(StoreContext context, Integer outcome) { @@ -125,7 +120,7 @@ public int call(StoreContext context) { public final VerifyParameter verifyParameter; - VerifyFunction verify = VerifyFunction.EMPTY; + VerifyFunction verify; VerifyCallbackFunction verifyCallback = VerifyCallbackFunction.EMPTY; GetIssuerFunction getIssuer = GetIssuerFunction.EMPTY; @@ -162,10 +157,6 @@ public VerifyParameter getVerifyParameter() { return verifyParameter; } - public VerifyFunction getVerifyFunction() { - return verify; - } - /** * c: X509_STORE_set_verify_func */ diff --git a/src/main/java/org/jruby/ext/openssl/x509store/StoreContext.java b/src/main/java/org/jruby/ext/openssl/x509store/StoreContext.java index 8ae3119f..2dd12a76 100644 --- a/src/main/java/org/jruby/ext/openssl/x509store/StoreContext.java +++ b/src/main/java/org/jruby/ext/openssl/x509store/StoreContext.java @@ -263,7 +263,7 @@ public int init(X509AuxCertificate cert, List chain) { if ( store.verifyCallback != null && store.verifyCallback != Store.VerifyCallbackFunction.EMPTY ) { this.verifyCallback = store.verifyCallback; } - if ( store.verify != null && store.verify != Store.VerifyFunction.EMPTY) { + if ( store.verify != null ) { this.verify = store.verify; } if ( store.checkRevocation != null && store.checkRevocation != Store.CheckRevocationFunction.EMPTY) { @@ -863,7 +863,7 @@ int verify_chain_legacy() throws Exception { if ( ok == 0 ) return ok; /* At this point, we have a chain and need to verify it */ - if ( verify != null && verify != Store.VerifyFunction.EMPTY ) { + if ( verify != null ) { ok = verify.call(this); } else { ok = internalVerify.call(this); From c63c9d2d0254c77458e29776887640e65d787c52 Mon Sep 17 00:00:00 2001 From: kares Date: Wed, 13 Oct 2021 18:23:09 +0200 Subject: [PATCH 19/63] restore old internal_verify and do not use new in legacy --- .../ext/openssl/x509store/StoreContext.java | 216 +++++++++++------- 1 file changed, 136 insertions(+), 80 deletions(-) diff --git a/src/main/java/org/jruby/ext/openssl/x509store/StoreContext.java b/src/main/java/org/jruby/ext/openssl/x509store/StoreContext.java index 2dd12a76..68100a29 100644 --- a/src/main/java/org/jruby/ext/openssl/x509store/StoreContext.java +++ b/src/main/java/org/jruby/ext/openssl/x509store/StoreContext.java @@ -907,7 +907,7 @@ int verify_chain() throws Exception { //} /* Verify chain signatures and expiration times */ - ok = verify != null ? verify.call(this) : internalVerify.call(this); + ok = verify != null ? verify.call(this) : internal_verify(); if (ok == 0) return ok; //if ((ok = check_name_constraints(ctx)) == 0) @@ -1871,105 +1871,161 @@ public int call(StoreContext context, Integer outcome) { /* * c: static int internal_verify(X509_STORE_CTX *ctx) */ - final static Store.VerifyFunction internalVerify = new Store.VerifyFunction() { - public int call(final StoreContext ctx) throws Exception { - int n = ctx.chain.size() - 1; - X509AuxCertificate xi = ctx.chain.get(n); - X509AuxCertificate xs; + private int internal_verify() throws Exception { + int n = chain.size() - 1; + X509AuxCertificate xi = chain.get(n); + X509AuxCertificate xs; - if (ctx.checkIssued.call(ctx, xi, xi) != 0) { + if (check_issued(xi, xi)) { + xs = xi; + } else { + if ((getParam().flags & V_FLAG_PARTIAL_CHAIN) != 0) { xs = xi; - } else { - if ((ctx.getParam().flags & V_FLAG_PARTIAL_CHAIN) != 0) { - xs = xi; - // goto check_cert; - if (!check_cert(ctx, xi, xs, n)) { - return 0; - } - if (--n >= 0) { - xi = xs; - // xs = ctx.chain.get(n); - } - // goto end + // goto check_cert; + if (!internal_verify_check_cert(this, xi, xs, n)) { + return 0; } - if (n <= 0) { - return ctx.verify_cb_cert(xi, 0, V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE); + if (--n >= 0) { + xi = xs; + // xs = ctx.chain.get(n); } - - n--; - ctx.errorDepth = n; - xs = ctx.chain.get(n); + // goto end + } + if (n <= 0) { + return verify_cb_cert(xi, 0, V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE); } + n--; + errorDepth = n; + xs = chain.get(n); + } + + /* + * Do not clear ctx->error=0, it must be "sticky", only the user's callback + * is allowed to reset errors (at its own peril). + */ + while ( n >= 0 ) { /* - * Do not clear ctx->error=0, it must be "sticky", only the user's callback - * is allowed to reset errors (at its own peril). + * Skip signature check for self signed certificates unless explicitly + * asked for. It doesn't add any security and just wastes time. If + * the issuer's public key is unusable, report the issuer certificate + * and its depth (rather than the depth of the subject). */ - while ( n >= 0 ) { - /* - * Skip signature check for self signed certificates unless explicitly - * asked for. It doesn't add any security and just wastes time. If - * the issuer's public key is unusable, report the issuer certificate - * and its depth (rather than the depth of the subject). - */ - if (xs != xi || (ctx.getParam().flags & V_FLAG_CHECK_SS_SIGNATURE) != 0) { - PublicKey pkey = xi.getPublicKey(); - if (pkey == null) { - if (ctx.verify_cb_cert(xi, xi != xs ? n+1 : n, V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY) == 0) - return 0; - } else if (!X509_verify(xs, pkey)) { - if (ctx.verify_cb_cert(xs, n, V_ERR_CERT_SIGNATURE_FAILURE) == 0) - return 0; - } + if (xs != xi || (getParam().flags & V_FLAG_CHECK_SS_SIGNATURE) != 0) { + PublicKey pkey = xi.getPublicKey(); + if (pkey == null) { + if (verify_cb_cert(xi, xi != xs ? n+1 : n, V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY) == 0) + return 0; + } else if (!X509_verify(xs, pkey)) { + if (verify_cb_cert(xs, n, V_ERR_CERT_SIGNATURE_FAILURE) == 0) + return 0; } + } - // check_cert : - if (!check_cert(ctx, xi, xs, n)) { - return 0; - } - if (--n >= 0) { - xi = xs; - xs = ctx.chain.get(n); - } - // end + // check_cert : + if (!internal_verify_check_cert(this, xi, xs, n)) { + return 0; } - return 1; + if (--n >= 0) { + xi = xs; + xs = chain.get(n); + } + // end } + return 1; + } - // goto check_cert: - private boolean check_cert(final StoreContext ctx, X509AuxCertificate xi, X509AuxCertificate xs, int n) + // goto check_cert: + private static boolean internal_verify_check_cert( + final StoreContext ctx, X509AuxCertificate xi, X509AuxCertificate xs, int n) throws Exception { - /* Calls verify callback as needed */ - if (!ctx.x509_check_cert_time(xs, n)) - return false; + /* Calls verify callback as needed */ + if (!ctx.x509_check_cert_time(xs, n)) + return false; - /* - * Signal success at this depth. However, the previous error (if any) - * is retained. - */ - ctx.currentIssuer = xi; - ctx.currentCertificate = xs; - ctx.errorDepth = n; - if (ctx.verifyCallback.call(ctx, 1) == 0) - return false; - - return true; // do not halt yet but : - //if (--n >= 0) { - // xi = xs; - // xs = ctx.chain.get(n); - //} + /* + * Signal success at this depth. However, the previous error (if any) + * is retained. + */ + ctx.currentIssuer = xi; + ctx.currentCertificate = xs; + ctx.errorDepth = n; + if (ctx.verifyCallback.call(ctx, 1) == 0) + return false; + + return true; // do not halt yet but : + //if (--n >= 0) { + // xi = xs; + // xs = ctx.chain.get(n); + //} + } + + private static boolean X509_verify(X509AuxCertificate xs, PublicKey pkey) { + if (xs.verified) return true; + + try { + xs.verify(pkey); + } catch (Exception e) { + return false; } + return xs.verified = true; + } - private boolean X509_verify(X509AuxCertificate xs, PublicKey pkey) { - if (xs.verified) return true; + @Deprecated // legacy internal_verify + final static Store.VerifyFunction internalVerify = new Store.VerifyFunction() { + public int call(final StoreContext context) throws Exception { + Store.VerifyCallbackFunction verifyCallback = context.verifyCallback; - try { - xs.verify(pkey); + int n = context.chain.size(); + context.errorDepth = n - 1; + n--; + X509AuxCertificate xi = context.chain.get(n); + X509AuxCertificate xs = null; + int ok; + + if (context.checkIssued.call(context, xi, xi) != 0) { + xs = xi; + } else { + if (n <= 0) { + context.error = X509Utils.V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE; + context.currentCertificate = xi; + ok = verifyCallback.call(context, ZERO); + return ok; + } else { + n--; + context.errorDepth = n; + xs = context.chain.get(n); + } } - catch (Exception e) { - return false; + + while (n >= 0) { + context.errorDepth = n; + if (!X509_verify(xs, xi.getPublicKey())) { + context.error = X509Utils.V_ERR_CERT_SIGNATURE_FAILURE; + context.currentCertificate = xs; + ok = verifyCallback.call(context, ZERO); + if (ok == 0) return ok; + } + + //ok = context.checkCertificateTime(xs); + //if (ok == 0) return ok; + // + //context.currentIssuer = xi; + //context.currentCertificate = xs; + //ok = verifyCallback.call(context, 1); + //if (ok == 0) return ok; + if (!internal_verify_check_cert(context, xi, xs, n)) { + return 0; + } + + n--; + if (n >= 0) { + xi = xs; + xs = context.chain.get(n); + } } - return xs.verified = true; + ok = 1; + return ok; } }; From 41ce9d2ed8eec24c41f22318a2f0b255e1aeabb4 Mon Sep 17 00:00:00 2001 From: kares Date: Wed, 13 Oct 2021 20:31:04 +0200 Subject: [PATCH 20/63] [refactor] drop all EMPTY fns --- .../ext/openssl/x509store/Function2.java | 6 -- .../ext/openssl/x509store/Function3.java | 6 -- .../jruby/ext/openssl/x509store/Store.java | 91 +++++-------------- .../ext/openssl/x509store/StoreContext.java | 61 +++++++------ 4 files changed, 56 insertions(+), 108 deletions(-) diff --git a/src/main/java/org/jruby/ext/openssl/x509store/Function2.java b/src/main/java/org/jruby/ext/openssl/x509store/Function2.java index 8949a901..95d3f1c3 100644 --- a/src/main/java/org/jruby/ext/openssl/x509store/Function2.java +++ b/src/main/java/org/jruby/ext/openssl/x509store/Function2.java @@ -33,11 +33,5 @@ * @author Ola Bini */ interface Function2 { - static class Empty implements Function2 { - public int call(Object arg0, Object arg1) { - return -1; - } - } - public static final Function2.Empty EMPTY = new Empty(); int call(T arg0, U arg1) throws Exception; }// Function2 diff --git a/src/main/java/org/jruby/ext/openssl/x509store/Function3.java b/src/main/java/org/jruby/ext/openssl/x509store/Function3.java index e7a51454..cdffc5d2 100644 --- a/src/main/java/org/jruby/ext/openssl/x509store/Function3.java +++ b/src/main/java/org/jruby/ext/openssl/x509store/Function3.java @@ -33,11 +33,5 @@ * @author Ola Bini */ interface Function3 { - static class Empty implements Function3 { - public int call(Object arg0,Object arg1,Object arg2) { - return -1; - } - } - public static final Function3.Empty EMPTY = new Empty(); int call(T arg0, U arg1, V arg2) throws Exception; }// Function3 diff --git a/src/main/java/org/jruby/ext/openssl/x509store/Store.java b/src/main/java/org/jruby/ext/openssl/x509store/Store.java index ce4c200a..9034164f 100644 --- a/src/main/java/org/jruby/ext/openssl/x509store/Store.java +++ b/src/main/java/org/jruby/ext/openssl/x509store/Store.java @@ -53,62 +53,21 @@ public class Store implements X509TrustManager { public interface VerifyFunction extends Function1 { } - public static interface VerifyCallbackFunction extends Function2 { - public static final VerifyCallbackFunction EMPTY = new VerifyCallbackFunction(){ - public int call(StoreContext context, Integer outcome) { - return -1; - } - }; - } - static interface GetIssuerFunction extends Function3 { - public static final GetIssuerFunction EMPTY = new GetIssuerFunction(){ - public int call(StoreContext context, X509AuxCertificate[] issuer, X509AuxCertificate cert) { - return -1; - } - }; - } - static interface CheckIssuedFunction extends Function3 { - public static final CheckIssuedFunction EMPTY = new CheckIssuedFunction(){ - public int call(StoreContext context, X509AuxCertificate cert, X509AuxCertificate issuer) throws Exception { - return -1; - } - }; - } - static interface CheckRevocationFunction extends Function1 { - public static final CheckRevocationFunction EMPTY = new CheckRevocationFunction(){ - public int call(StoreContext context) { - return -1; - } - }; - } - static interface GetCRLFunction extends Function3 { - public static final GetCRLFunction EMPTY = new GetCRLFunction(){ - public int call(StoreContext context, java.security.cert.X509CRL[] crls, X509AuxCertificate cert) { - return -1; - } - }; - } - static interface CheckCRLFunction extends Function2 { - public static final CheckCRLFunction EMPTY = new CheckCRLFunction(){ - public int call(StoreContext context, java.security.cert.X509CRL crl) { - return -1; - } - }; - } - static interface CertificateCRLFunction extends Function3 { - public static final CertificateCRLFunction EMPTY = new CertificateCRLFunction(){ - public int call(StoreContext context, java.security.cert.X509CRL crl, X509AuxCertificate cert) { - return -1; - } - }; - } - static interface CleanupFunction extends Function1 { - public static final CleanupFunction EMPTY = new CleanupFunction(){ - public int call(StoreContext context) { - return -1; - } - }; - } + public interface VerifyCallbackFunction extends Function2 { } + + interface GetIssuerFunction extends Function3 { } + + interface CheckIssuedFunction extends Function3 { } + + interface CheckRevocationFunction extends Function1 { } + + interface GetCRLFunction extends Function3 { } + + interface CheckCRLFunction extends Function2 { } + + interface CertificateCRLFunction extends Function3 { } + + interface CleanupFunction extends Function1 { } // @Deprecated int cache = 1; // not-used @@ -121,15 +80,15 @@ public int call(StoreContext context) { public final VerifyParameter verifyParameter; VerifyFunction verify; - VerifyCallbackFunction verifyCallback = VerifyCallbackFunction.EMPTY; + VerifyCallbackFunction verifyCallback; - GetIssuerFunction getIssuer = GetIssuerFunction.EMPTY; - CheckIssuedFunction checkIssued = CheckIssuedFunction.EMPTY; - CheckRevocationFunction checkRevocation = CheckRevocationFunction.EMPTY; - GetCRLFunction getCRL = GetCRLFunction.EMPTY; - CheckCRLFunction checkCRL = CheckCRLFunction.EMPTY; - CertificateCRLFunction certificateCRL = CertificateCRLFunction.EMPTY; - CleanupFunction cleanup = CleanupFunction.EMPTY; + GetIssuerFunction getIssuer; + CheckIssuedFunction checkIssued; + CheckRevocationFunction checkRevocation; + GetCRLFunction getCRL; + CheckCRLFunction checkCRL; + CertificateCRLFunction certificateCRL; + CleanupFunction cleanup; private final List extraData; @@ -164,10 +123,6 @@ public void setVerifyFunction(VerifyFunction func) { verify = func; } - public VerifyCallbackFunction getVerifyCallback() { - return verifyCallback; - } - /** * c: X509_STORE_set_verify_cb_func */ diff --git a/src/main/java/org/jruby/ext/openssl/x509store/StoreContext.java b/src/main/java/org/jruby/ext/openssl/x509store/StoreContext.java index 68100a29..0f4d6622 100644 --- a/src/main/java/org/jruby/ext/openssl/x509store/StoreContext.java +++ b/src/main/java/org/jruby/ext/openssl/x509store/StoreContext.java @@ -213,35 +213,20 @@ public int init(X509AuxCertificate cert, List chain) { this.otherContext = null; this.isValid = false; this.chain = null; - this.error = 0; + this.error = V_OK; this.explicitPolicy = 0; this.errorDepth = 0; this.currentCertificate = null; this.currentIssuer = null; + this.currentCRL = null; this.tree = null; + this.parent = null; - this.verifyParameter = new VerifyParameter(); - + /* store->cleanup is always 0 in OpenSSL, if set must be idempotent */ if ( store != null ) { - ret = verifyParameter.inherit(store.verifyParameter); + this.cleanup = store.cleanup; } else { - verifyParameter.flags |= X509Utils.X509_VP_FLAG_DEFAULT | X509Utils.X509_VP_FLAG_ONCE; - } - - if ( store != null ) { - verifyCallback = store.getVerifyCallback(); - cleanup = store.cleanup; - } else { - cleanup = Store.CleanupFunction.EMPTY; - } - - if ( ret != 0 ) { - ret = verifyParameter.inherit(VerifyParameter.lookup("default")); - } - - if ( ret == 0 ) { - X509Error.addError(X509Utils.ERR_R_MALLOC_FAILURE); - return 0; + this.cleanup = null; } this.checkIssued = defaultCheckIssued; @@ -254,33 +239,53 @@ public int init(X509AuxCertificate cert, List chain) { this.certificateCRL = defaultCertificateCRL; if ( store != null ) { - if ( store.checkIssued != null && store.checkIssued != Store.CheckIssuedFunction.EMPTY ) { + if ( store.checkIssued != null ) { this.checkIssued = store.checkIssued; } - if ( store.getIssuer != null && store.getIssuer != Store.GetIssuerFunction.EMPTY ) { + if ( store.getIssuer != null ) { this.getIssuer = store.getIssuer; } - if ( store.verifyCallback != null && store.verifyCallback != Store.VerifyCallbackFunction.EMPTY ) { + if ( store.verifyCallback != null ) { this.verifyCallback = store.verifyCallback; } if ( store.verify != null ) { this.verify = store.verify; } - if ( store.checkRevocation != null && store.checkRevocation != Store.CheckRevocationFunction.EMPTY) { + if ( store.checkRevocation != null ) { this.checkRevocation = store.checkRevocation; } - if ( store.getCRL != null && store.getCRL != Store.GetCRLFunction.EMPTY) { + if ( store.getCRL != null ) { this.getCRL = store.getCRL; } - if( store.checkCRL != null && store.checkCRL != Store.CheckCRLFunction.EMPTY) { + if( store.checkCRL != null ) { this.checkCRL = store.checkCRL; } - if ( store.certificateCRL != null && store.certificateCRL != Store.CertificateCRLFunction.EMPTY) { + if ( store.certificateCRL != null ) { this.certificateCRL = store.certificateCRL; } } + // store->check_policy this.checkPolicy = defaultCheckPolicy; + // store->lookup_certs + // store->lookup_crls + + this.verifyParameter = new VerifyParameter(); + + if ( store != null ) { + ret = verifyParameter.inherit(store.verifyParameter); + } else { + verifyParameter.flags |= X509Utils.X509_VP_FLAG_DEFAULT | X509Utils.X509_VP_FLAG_ONCE; + } + + if ( ret != 0 ) { + ret = verifyParameter.inherit(VerifyParameter.lookup("default")); + } + + if ( ret == 0 ) { + X509Error.addError(X509Utils.ERR_R_MALLOC_FAILURE); + return 0; + } // getExtraData(); return 1; From 082aab7921649465963b87c54d2e607d29e616ee Mon Sep 17 00:00:00 2001 From: kares Date: Wed, 13 Oct 2021 21:00:25 +0200 Subject: [PATCH 21/63] [fix] fns that might be inherited from store --- .../ext/openssl/x509store/StoreContext.java | 141 +++++++++--------- 1 file changed, 68 insertions(+), 73 deletions(-) diff --git a/src/main/java/org/jruby/ext/openssl/x509store/StoreContext.java b/src/main/java/org/jruby/ext/openssl/x509store/StoreContext.java index 0f4d6622..c880c30e 100644 --- a/src/main/java/org/jruby/ext/openssl/x509store/StoreContext.java +++ b/src/main/java/org/jruby/ext/openssl/x509store/StoreContext.java @@ -229,11 +229,11 @@ public int init(X509AuxCertificate cert, List chain) { this.cleanup = null; } - this.checkIssued = defaultCheckIssued; + this.checkIssued = VERIFY_LEGACY ? check_issued_legacy : check_issued; this.getIssuer = getFirstIssuer; this.verifyCallback = nullCallback; - this.verify = internalVerify; - this.checkRevocation = defaultCheckRevocation; + this.verify = null; + this.checkRevocation = StoreContext.check_revocation; this.getCRL = defaultGetCRL; this.checkCRL = defaultCheckCRL; this.certificateCRL = defaultCertificateCRL; @@ -266,7 +266,7 @@ public int init(X509AuxCertificate cert, List chain) { } // store->check_policy - this.checkPolicy = defaultCheckPolicy; + this.checkPolicy = StoreContext.check_policy; // store->lookup_certs // store->lookup_crls @@ -303,7 +303,7 @@ public void trustedStack(List sk) { * c: X509_STORE_CTX_cleanup */ public void cleanup() throws Exception { - if (cleanup != null && cleanup != Store.CleanupFunction.EMPTY) { + if (cleanup != null) { cleanup.call(this); } verifyParameter = null; @@ -902,7 +902,7 @@ int verify_chain() throws Exception { //(ok = check_auth_level(ctx)) == 0 || //(ok = check_id()) == 0 || 1) ); - if (ok == 0 || (ok = check_revocation()) == 0) + if (ok == 0 || (ok = checkRevocation.call(this)) == 0) return ok; //err = X509_chain_check_suiteb(&ctx->error_depth, NULL, ctx->chain, ctx->param->flags); @@ -920,7 +920,7 @@ int verify_chain() throws Exception { /* If we get this far evaluate policies */ if ((getParam().flags & V_FLAG_POLICY_CHECK) != 0) { - ok = check_policy(); + ok = checkPolicy.call(this); } return ok; } @@ -1227,7 +1227,7 @@ private X509AuxCertificate find_issuer(List sk, X509AuxCerti X509AuxCertificate rv = null; for (X509AuxCertificate issuer : sk) { - if (check_issued(x, issuer)) { + if (checkIssued.call(this, x, issuer) != 0) { rv = issuer; if (x509_check_cert_time(rv, -1)) break; } @@ -1235,32 +1235,6 @@ private X509AuxCertificate find_issuer(List sk, X509AuxCerti return rv; } - /* - * Given a possible certificate and issuer check them - * - * x509_vfy.c: static int check_issued(X509_STORE_CTX *ctx, X509 *x, X509 *issuer) - */ - private boolean check_issued(X509AuxCertificate x, X509AuxCertificate issuer) throws Exception { - int ret; - if (x == issuer) return checkIssued.call(this, x, x) != 0; // cert_self_signed(x) - ret = checkIfIssuedBy(issuer, x); - if (ret == V_OK) { - /* Special case: single self signed certificate */ - boolean ss = checkIssued.call(this, x, x) != 0; // cert_self_signed(x) - if (ss && chain.size() == 1) return true; - - //for (int i = 0; i < chain.size(); i++) { - // X509AuxCertificate ch = chain.get(i); - // if (ch == issuer || ch.equals(issuer)) { - // ret = V_ERR_PATH_LOOP; - // break; - // } - //} - } - - return (ret == V_OK); - } - private final static Set CRITICAL_EXTENSIONS = new HashSet(8); static { CRITICAL_EXTENSIONS.add("2.16.840.1.113730.1.1"); // netscape cert type, NID 71 @@ -1577,9 +1551,13 @@ private int check_chain_extensions() throws Exception { return 1; } - private boolean isSelfIssued(final X509AuxCertificate x) throws Exception { - // (x->ex_flags & EXFLAG_SI)) - return checkIssued.call(this, x, x) != 0; // TODO self-signed == self-issued? + /* Return 1 is a certificate is self signed */ + private boolean cert_self_signed(X509AuxCertificate x) throws CertificateException, IOException { + Purpose.checkPurpose(x, -1, 0); + if ((x.getExFlags() & EXFLAG_SS) != 0) { + return true; + } + return false; } @Deprecated // legacy check_trust @@ -1845,10 +1823,37 @@ public int call(StoreContext context, X509AuxCertificate[] issuer, X509AuxCertif } }; - /** - * c: check_issued + /* + * Given a possible certificate and issuer check them + * + * x509_vfy.c: static int check_issued(X509_STORE_CTX *ctx, X509 *x, X509 *issuer) */ - final static Store.CheckIssuedFunction defaultCheckIssued = new Store.CheckIssuedFunction() { + + // TODO logic mismtach - check store.checkIssued logic or always use legacy + + final static Store.CheckIssuedFunction check_issued = new Store.CheckIssuedFunction() { + public int call(StoreContext ctx, X509AuxCertificate x, X509AuxCertificate issuer) throws Exception { + int ret; + if (x == issuer) return ctx.cert_self_signed(x) ? 1 : 0; + ret = checkIfIssuedBy(issuer, x); + if (ret == V_OK) { + /* Special case: single self signed certificate */ + if (ctx.cert_self_signed(x) && ctx.chain.size() == 1) return 1; + + //for (int i = 0; i < chain.size(); i++) { + // X509AuxCertificate ch = chain.get(i); + // if (ch == issuer || ch.equals(issuer)) { + // ret = V_ERR_PATH_LOOP; + // break; + // } + //} + } + + return (ret == V_OK) ? 1 : 0; + } + }; + + final static Store.CheckIssuedFunction check_issued_legacy = new Store.CheckIssuedFunction() { public int call(StoreContext context, X509AuxCertificate cert, X509AuxCertificate issuer) throws Exception { int ret = X509Utils.checkIfIssuedBy(issuer, cert); if ( ret == X509Utils.V_OK ) return 1; @@ -1881,7 +1886,7 @@ private int internal_verify() throws Exception { X509AuxCertificate xi = chain.get(n); X509AuxCertificate xs; - if (check_issued(xi, xi)) { + if (checkIssued.call(this, xi, xi) != 0) { xs = xi; } else { if ((getParam().flags & V_FLAG_PARTIAL_CHAIN) != 0) { @@ -2037,30 +2042,26 @@ public int call(final StoreContext context) throws Exception { /* * c: static int check_revocation(X509_STORE_CTX *ctx) */ - private int check_revocation() throws Exception { - if ( (getParam().flags & V_FLAG_CRL_CHECK) == 0 ) { + final static Store.CheckRevocationFunction check_revocation = new Store.CheckRevocationFunction() { + public int call(final StoreContext ctx) throws Exception { + if ( (ctx.getParam().flags & V_FLAG_CRL_CHECK) == 0 ) { + return 1; + } + final int last; + if ( (ctx.getParam().flags & V_FLAG_CRL_CHECK_ALL) != 0 ) { + last = ctx.chain.size() - 1; + } else { + /* If checking CRL paths this isn't the EE certificate */ + if (ctx.parent != null) return 1; // NOT IMPLEMENTED: always null + last = 0; + } + for ( int i=0; i<=last; i++ ) { + ctx.errorDepth = i; + int ok = ctx.checkCertificate(); // check_cert(ctx); + if (ok == 0) return 0; + } return 1; } - final int last; - if ( (getParam().flags & V_FLAG_CRL_CHECK_ALL) != 0 ) { - last = chain.size() - 1; - } else { - /* If checking CRL paths this isn't the EE certificate */ - if (parent != null) return 1; // NOT IMPLEMENTED: always null - last = 0; - } - for ( int i=0; i<=last; i++ ) { - errorDepth = i; - int ok = checkCertificate(); // check_cert(ctx); - if (ok == 0) return 0; - } - return 1; - } - - final static Store.CheckRevocationFunction defaultCheckRevocation = new Store.CheckRevocationFunction() { - public int call(final StoreContext context) throws Exception { - return context.check_revocation(); - } }; /** @@ -2168,17 +2169,11 @@ public int call(final StoreContext context, final X509CRL crl, X509AuxCertificat /* * c: static int check_policy(X509_STORE_CTX *ctx) */ - private int check_policy() throws Exception { - // NOTE: NOT IMPLEMENTED - return 1; - } - - /** - * c: check_policy - */ - final static CheckPolicyFunction defaultCheckPolicy = new CheckPolicyFunction() { + final static CheckPolicyFunction check_policy = new CheckPolicyFunction() { public int call(StoreContext context) throws Exception { - return context.check_policy(); + // NOTE: NOT IMPLEMENTED + return 1; } }; + }// X509_STORE_CTX From 950d806d3a0e980e9481dc8d91fa47a5a5858423 Mon Sep 17 00:00:00 2001 From: kares Date: Wed, 13 Oct 2021 21:02:03 +0200 Subject: [PATCH 22/63] a toString helper for debugging --- .../ext/openssl/x509store/VerifyParameter.java | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/main/java/org/jruby/ext/openssl/x509store/VerifyParameter.java b/src/main/java/org/jruby/ext/openssl/x509store/VerifyParameter.java index 0234f227..0708e3b4 100644 --- a/src/main/java/org/jruby/ext/openssl/x509store/VerifyParameter.java +++ b/src/main/java/org/jruby/ext/openssl/x509store/VerifyParameter.java @@ -257,6 +257,20 @@ public int addTable() { return 1; } + @Override + public String toString() { + return "VerifyParameter{" + + "name='" + name + '\'' + + ", checkTime=" + checkTime + + ", inheritFlags=" + inheritFlags + + ", flags=" + flags + + ", purpose=" + purpose + + ", trust=" + trust + + ", depth=" + depth + + ", policies=" + policies + + '}'; + } + public static VerifyParameter lookup(String name) { for(VerifyParameter v : parameterTable) { if(name.equals(v.name)) { From 9d17bb7c5da0af5a44febbcc17ddc4fa35551b34 Mon Sep 17 00:00:00 2001 From: kares Date: Wed, 13 Oct 2021 21:01:32 +0200 Subject: [PATCH 23/63] implement some ex_flags on certificate --- .../jruby/ext/openssl/OCSPBasicResponse.java | 3 + .../ext/openssl/x509store/StoreContext.java | 2 + .../openssl/x509store/X509AuxCertificate.java | 76 +++++++++++++++++-- .../ext/openssl/x509store/X509Utils.java | 25 +++--- 4 files changed, 90 insertions(+), 16 deletions(-) diff --git a/src/main/java/org/jruby/ext/openssl/OCSPBasicResponse.java b/src/main/java/org/jruby/ext/openssl/OCSPBasicResponse.java index 8e07b52e..413de4dd 100644 --- a/src/main/java/org/jruby/ext/openssl/OCSPBasicResponse.java +++ b/src/main/java/org/jruby/ext/openssl/OCSPBasicResponse.java @@ -530,6 +530,9 @@ private boolean checkDelegated(X509Cert signerCA) { catch (CertificateParsingException e) { throw newOCSPError(getRuntime(), e); } + catch (IOException e) { + throw newOCSPError(getRuntime(), e); + } } private boolean matchIssuerId(X509Cert signerCA, CertificateID certId, List singleResponses) throws IOException { diff --git a/src/main/java/org/jruby/ext/openssl/x509store/StoreContext.java b/src/main/java/org/jruby/ext/openssl/x509store/StoreContext.java index c880c30e..d19b92ea 100644 --- a/src/main/java/org/jruby/ext/openssl/x509store/StoreContext.java +++ b/src/main/java/org/jruby/ext/openssl/x509store/StoreContext.java @@ -27,8 +27,10 @@ ***** END LICENSE BLOCK *****/ package org.jruby.ext.openssl.x509store; +import java.io.IOException; import java.security.GeneralSecurityException; import java.security.PublicKey; +import java.security.cert.CertificateException; import java.security.cert.X509CRL; import java.security.cert.X509Certificate; import java.security.cert.X509Extension; diff --git a/src/main/java/org/jruby/ext/openssl/x509store/X509AuxCertificate.java b/src/main/java/org/jruby/ext/openssl/x509store/X509AuxCertificate.java index 184d06ba..2587cc4f 100644 --- a/src/main/java/org/jruby/ext/openssl/x509store/X509AuxCertificate.java +++ b/src/main/java/org/jruby/ext/openssl/x509store/X509AuxCertificate.java @@ -31,6 +31,7 @@ import java.io.ByteArrayInputStream; import java.math.BigInteger; +import java.util.Arrays; import java.util.Date; import java.util.Collection; import java.util.List; @@ -52,9 +53,15 @@ import javax.security.auth.x500.X500Principal; import org.bouncycastle.asn1.ASN1InputStream; +import org.bouncycastle.asn1.ASN1OctetString; +import org.bouncycastle.asn1.ASN1Sequence; import org.bouncycastle.asn1.DERBitString; import org.bouncycastle.asn1.DEROctetString; +import org.bouncycastle.asn1.DERTaggedObject; +import org.bouncycastle.asn1.DLSequence; +import org.bouncycastle.asn1.x509.AuthorityKeyIdentifier; import org.bouncycastle.asn1.x509.Certificate; +import org.bouncycastle.asn1.x509.SubjectKeyIdentifier; import org.bouncycastle.jce.provider.X509CertificateObject; import org.jruby.ext.openssl.SecurityHelper; @@ -74,7 +81,7 @@ public class X509AuxCertificate extends X509Certificate implements Cloneable { final X509Aux aux; boolean verified = false; // opt: avoids doing internal_verify twice - private int ex_flags = 0; + private int ex_flags = -1; public X509AuxCertificate(Certificate wrap) throws IOException, CertificateException { super(); @@ -106,16 +113,75 @@ public final X509AuxCertificate clone() { final X509AuxCertificate cloneForCache() { final X509AuxCertificate clone = clone(); clone.verified = false; - clone.ex_flags = 0; + clone.ex_flags = -1; return clone; } - public int getExFlags() { + public int getExFlags() throws IOException { + if (ex_flags == -1) { + //try { + ex_flags = computeExFlags(); + //} catch (IOException e) { + // throw new IllegalStateException(e); + //} + } return ex_flags; } - public void setExFlags(int ex_flags) { - this.ex_flags = ex_flags; + // NOTE: not all EXFLAGS are implemented! + private int computeExFlags() throws IOException { + int flags = 0; + + /* V1 should mean no extensions ... */ + if (getVersion() == 1) { + flags |= X509Utils.EXFLAG_V1; + } + + if (getExtensionValue("2.5.29.19") != null) { // BASIC_CONSTRAINTS + if (getBasicConstraints() != -1) { // is CA + flags |= X509Utils.EXFLAG_CA; + } + flags |= X509Utils.EXFLAG_BCONS; + } + + if (getSubjectX500Principal().equals(getIssuerX500Principal())) { + flags |= X509Utils.EXFLAG_SI; /* Cert is self-issued */ + + // TODO duplicate code from X509Utils.checkIfIssuedBy + if (getExtensionValue("2.5.29.35") != null) { //authorityKeyID + Object key = X509Utils.get(getExtensionValue("2.5.29.35")); + if (!(key instanceof ASN1Sequence)) key = X509Utils.get((DEROctetString) key); + + final ASN1Sequence seq = (ASN1Sequence) key; + final AuthorityKeyIdentifier akid; + if (seq.size() == 1 && (seq.getObjectAt(0) instanceof ASN1OctetString)) { + akid = AuthorityKeyIdentifier.getInstance(new DLSequence(new DERTaggedObject(0, seq.getObjectAt(0)))); + } else { + akid = AuthorityKeyIdentifier.getInstance(seq); + } + + if (akid.getKeyIdentifier() != null) { + if (getExtensionValue("2.5.29.14") != null) { + DEROctetString der = (DEROctetString) X509Utils.get(getExtensionValue("2.5.29.14")); + SubjectKeyIdentifier skid = SubjectKeyIdentifier.getInstance(X509Utils.get(der.getOctets())); + if (skid.getKeyIdentifier() != null) { + if (Arrays.equals(akid.getKeyIdentifier(), skid.getKeyIdentifier())) { /* SKID matches AKID */ + /* .. and the signature alg matches the PUBKEY alg: */ + if (getSigAlgName().equals(getPublicKey().getAlgorithm())) { + flags |= X509Utils.EXFLAG_SS; /* indicate self-signed */ + } + } + } + } + } + } + } + + if (getKeyUsage() != null) { + flags |= X509Utils.EXFLAG_XKUSAGE; + } + + return flags; } // DELEGATES : diff --git a/src/main/java/org/jruby/ext/openssl/x509store/X509Utils.java b/src/main/java/org/jruby/ext/openssl/x509store/X509Utils.java index 5424f979..601789b5 100644 --- a/src/main/java/org/jruby/ext/openssl/x509store/X509Utils.java +++ b/src/main/java/org/jruby/ext/openssl/x509store/X509Utils.java @@ -197,11 +197,11 @@ public static String verifyCertificateErrorString(final int error) { } } - private static ASN1Primitive get(DEROctetString str) throws IOException { + static ASN1Primitive get(DEROctetString str) throws IOException { return get( str.getOctets() ); } - private static ASN1Primitive get(final byte[] input) throws IOException { + static ASN1Primitive get(final byte[] input) throws IOException { return new ASN1InputStream(input).readObject(); } @@ -624,19 +624,22 @@ else if (maybeCertFile != null && new File(maybeCertFile).exists()) { public static final int ERR_R_DISABLED=(5|ERR_R_FATAL); public static final int EXFLAG_BCONS=0x1; - public static final int EXFLAG_KUSAGE=0x2; + //public static final int EXFLAG_KUSAGE=0x2; public static final int EXFLAG_XKUSAGE=0x4; - public static final int EXFLAG_NSCERT=0x8; + //public static final int EXFLAG_NSCERT=0x8; public static final int EXFLAG_CA=0x10; - public static final int EXFLAG_SS=0x20; + public static final int EXFLAG_SI=0x20; /* self-issued, maybe not self-signed */ public static final int EXFLAG_V1=0x40; - public static final int EXFLAG_INVALID=0x80; - public static final int EXFLAG_SET=0x100; - public static final int EXFLAG_CRITICAL=0x200; - public static final int EXFLAG_PROXY=0x400; - - public static final int EXFLAG_INVALID_POLICY=0x400; + //public static final int EXFLAG_INVALID=0x80; + /* EXFLAG_SET is set to indicate that some values have been precomputed */ + //public static final int EXFLAG_SET=0x100; + //public static final int EXFLAG_CRITICAL=0x200; + //public static final int EXFLAG_PROXY=0x400; + + //public static final int EXFLAG_INVALID_POLICY=0x800; + //public static final int EXFLAG_FRESHEST=0x1000; + public static final int EXFLAG_SS=0x2000; /* cert is apparently self-signed */ public static final int XKU_SSL_SERVER=0x1; public static final int XKU_SSL_CLIENT=0x2; From b7ef6ae85cab5ace335c0d5b29579d088739c15c Mon Sep 17 00:00:00 2001 From: kares Date: Wed, 13 Oct 2021 21:07:53 +0200 Subject: [PATCH 24/63] review cert_self_signed usage for new verification --- .../jruby/ext/openssl/x509store/StoreContext.java | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/main/java/org/jruby/ext/openssl/x509store/StoreContext.java b/src/main/java/org/jruby/ext/openssl/x509store/StoreContext.java index d19b92ea..e4c69fa2 100644 --- a/src/main/java/org/jruby/ext/openssl/x509store/StoreContext.java +++ b/src/main/java/org/jruby/ext/openssl/x509store/StoreContext.java @@ -937,7 +937,7 @@ int verify_chain() throws Exception { int build_chain() throws Exception { int num = chain.size(); X509AuxCertificate cert = chain.get(num - 1); - boolean ss = checkIssued.call(this, cert, cert) != 0; // cert_self_signed(cert) + boolean ss = cert_self_signed(cert); short search; boolean may_trusted = false; boolean may_alternate = false; @@ -1067,7 +1067,7 @@ int build_chain() throws Exception { */ if (ss == false) { chain.add(x = xtmp); - ss = checkIssued.call(this, x, x) != 0; // cert_self_signed(x) + ss = cert_self_signed(x); } else if (num == num_untrusted) { /* * We have a self-signed certificate that has the same @@ -1169,7 +1169,7 @@ int build_chain() throws Exception { x = xtmp; num_untrusted++; - ss = checkIssued.call(this, xtmp, xtmp) != 0; // cert_self_signed(xtmp) + ss = cert_self_signed(xtmp); } } @@ -1505,7 +1505,8 @@ private int check_chain_extensions() throws Exception { return 0; /* Check pathlen if not self issued */ final int ex_pathlen = x.getBasicConstraints(); - if ((i > 1) && ex_pathlen != Integer.MAX_VALUE // !(x->ex_flags & EXFLAG_SI) + if ((i > 1) && (x.getExFlags() & EXFLAG_SI) == 0 + && ex_pathlen != Integer.MAX_VALUE && ex_pathlen != -1 && (plen > (ex_pathlen + proxy_path_length + 1))) { if (verify_cb_cert(x, i, V_ERR_PATH_LENGTH_EXCEEDED) == 0) @@ -1513,14 +1514,14 @@ private int check_chain_extensions() throws Exception { } /* Increment path length if not self issued */ - if (!isSelfIssued(x)) plen++; + if ((x.getExFlags() & EXFLAG_SI) == 0) plen++; /* * If this certificate is a proxy certificate, the next certificate * must be another proxy certificate or a EE certificate. If not, * the next certificate must be a CA certificate. */ - final byte[] ex_proxyCertInfo = x.getExtensionValue("1.3.6.1.5.5.7.1.14"); // id-pe-proxyCertInfo(14) + final byte[] ex_proxyCertInfo = x.getExtensionValue("1.3.6.1.5.5.7.1.14"); // id-pe-proxyCertInfo(14) if (ex_proxyCertInfo != null) { // x->ex_flags & EXFLAG_PROXY ASN1Sequence pci = (ASN1Sequence) new ASN1InputStream(ex_proxyCertInfo).readObject(); if (pci.size() > 0 && pci.getObjectAt(0) instanceof ASN1Integer) { From e947019386f5bdfbf71d03182d91f9db46a97971 Mon Sep 17 00:00:00 2001 From: kares Date: Thu, 14 Oct 2021 13:38:09 +0200 Subject: [PATCH 25/63] [refactor] get rid of remaining (confusing) NULL FNs --- .../org/jruby/ext/openssl/x509store/Function4.java | 6 ------ .../org/jruby/ext/openssl/x509store/Function5.java | 6 ------ .../java/org/jruby/ext/openssl/x509store/Lookup.java | 10 +++++----- 3 files changed, 5 insertions(+), 17 deletions(-) diff --git a/src/main/java/org/jruby/ext/openssl/x509store/Function4.java b/src/main/java/org/jruby/ext/openssl/x509store/Function4.java index 0726f297..8b213190 100644 --- a/src/main/java/org/jruby/ext/openssl/x509store/Function4.java +++ b/src/main/java/org/jruby/ext/openssl/x509store/Function4.java @@ -33,11 +33,5 @@ * @author Ola Bini */ interface Function4 { - static class Empty implements Function4 { - public int call(Object arg0,Object arg1,Object arg2,Object arg3) { - return -1; - } - } - public static final Function4.Empty EMPTY = new Empty(); int call(T arg0, U arg1, V arg2, X arg3) throws Exception; }// Function4 diff --git a/src/main/java/org/jruby/ext/openssl/x509store/Function5.java b/src/main/java/org/jruby/ext/openssl/x509store/Function5.java index 152e2fb7..c7fa7c6e 100644 --- a/src/main/java/org/jruby/ext/openssl/x509store/Function5.java +++ b/src/main/java/org/jruby/ext/openssl/x509store/Function5.java @@ -33,11 +33,5 @@ * @author Ola Bini */ interface Function5 { - static class Empty implements Function5 { - public int call(Object arg0,Object arg1,Object arg2,Object arg3,Object arg4) { - return -1; - } - } - public static final Function5.Empty EMPTY = new Empty(); int call(T arg0, U arg1, V arg2, X arg3, Y arg4) throws Exception; }// Function5 diff --git a/src/main/java/org/jruby/ext/openssl/x509store/Lookup.java b/src/main/java/org/jruby/ext/openssl/x509store/Lookup.java index 023fe756..02ac2948 100644 --- a/src/main/java/org/jruby/ext/openssl/x509store/Lookup.java +++ b/src/main/java/org/jruby/ext/openssl/x509store/Lookup.java @@ -128,7 +128,7 @@ public static LookupMethod fileLookup() { public int control(final int cmd, final String argc, final long argl, final String[] ret) throws Exception { if ( method == null ) return -1; - if ( method.control != null && method.control != Function5.EMPTY ) { + if ( method.control != null ) { return method.control.call(this, Integer.valueOf(cmd), argc, Long.valueOf(argl), ret); } return 1; @@ -384,7 +384,7 @@ public int init() throws Exception { * c: X509_LOOKUP_by_subject */ public int bySubject(final int type, final Name name, final X509Object[] ret) throws Exception { - if ( method == null || method.getBySubject == null || method.getBySubject == Function4.EMPTY ) { + if ( method == null || method.getBySubject == null ) { return X509_LU_FAIL; } if ( skip ) return 0; @@ -395,7 +395,7 @@ public int bySubject(final int type, final Name name, final X509Object[] ret) th * c: X509_LOOKUP_by_issuer_serial */ public int byIssuerSerialNumber(final int type, final Name name, final BigInteger serial, final X509Object[] ret) throws Exception { - if ( method == null || method.getByIssuerSerialNumber == null || method.getByIssuerSerialNumber == Function5.EMPTY ) { + if ( method == null || method.getByIssuerSerialNumber == null ) { return X509_LU_FAIL; } return method.getByIssuerSerialNumber.call(this, Integer.valueOf(type), name, serial, ret); @@ -405,7 +405,7 @@ public int byIssuerSerialNumber(final int type, final Name name, final BigIntege * c: X509_LOOKUP_by_fingerprint */ public int byFingerprint(final int type, final String bytes, final X509Object[] ret) throws Exception { - if ( method == null || method.getByFingerprint == null || method.getByFingerprint == Function4.EMPTY ) { + if ( method == null || method.getByFingerprint == null ) { return X509_LU_FAIL; } return method.getByFingerprint.call(this, Integer.valueOf(type), bytes, ret); @@ -415,7 +415,7 @@ public int byFingerprint(final int type, final String bytes, final X509Object[] * c: X509_LOOKUP_by_alias */ public int byAlias(final int type, final String alias, final X509Object[] ret) throws Exception { - if ( method == null || method.getByAlias == null || method.getByAlias == Function4.EMPTY ) { + if ( method == null || method.getByAlias == null ) { return X509_LU_FAIL; } return method.getByAlias.call(this, Integer.valueOf(type), alias, ret); From b86c549cd5f90719a865ed5e3be03cb6f9812775 Mon Sep 17 00:00:00 2001 From: kares Date: Thu, 14 Oct 2021 13:38:53 +0200 Subject: [PATCH 26/63] [refactor] reviewed message mappings --- .../ext/openssl/x509store/X509Utils.java | 99 ++++++++++--------- 1 file changed, 50 insertions(+), 49 deletions(-) diff --git a/src/main/java/org/jruby/ext/openssl/x509store/X509Utils.java b/src/main/java/org/jruby/ext/openssl/x509store/X509Utils.java index 601789b5..41a77d2d 100644 --- a/src/main/java/org/jruby/ext/openssl/x509store/X509Utils.java +++ b/src/main/java/org/jruby/ext/openssl/x509store/X509Utils.java @@ -105,93 +105,94 @@ public static String getDefaultCertificateFileEnvironment() { */ public static String verifyCertificateErrorString(final int error) { switch (error) { - case V_OK: return("ok"); - case V_ERR_UNABLE_TO_GET_ISSUER_CERT: + case V_OK: + return("ok"); + case V_ERR_UNABLE_TO_GET_ISSUER_CERT: return("unable to get issuer certificate"); - case V_ERR_UNABLE_TO_GET_CRL: + case V_ERR_UNABLE_TO_GET_CRL: return("unable to get certificate CRL"); - case V_ERR_UNABLE_TO_DECRYPT_CERT_SIGNATURE: + case V_ERR_UNABLE_TO_DECRYPT_CERT_SIGNATURE: return("unable to decrypt certificate's signature"); - case V_ERR_UNABLE_TO_DECRYPT_CRL_SIGNATURE: + case V_ERR_UNABLE_TO_DECRYPT_CRL_SIGNATURE: return("unable to decrypt CRL's signature"); - case V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY: + case V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY: return("unable to decode issuer public key"); - case V_ERR_CERT_SIGNATURE_FAILURE: + case V_ERR_CERT_SIGNATURE_FAILURE: return("certificate signature failure"); - case V_ERR_CRL_SIGNATURE_FAILURE: + case V_ERR_CRL_SIGNATURE_FAILURE: return("CRL signature failure"); - case V_ERR_CERT_NOT_YET_VALID: + case V_ERR_CERT_NOT_YET_VALID: return("certificate is not yet valid"); - case V_ERR_CRL_NOT_YET_VALID: + case V_ERR_CRL_NOT_YET_VALID: return("CRL is not yet valid"); - case V_ERR_CERT_HAS_EXPIRED: + case V_ERR_CERT_HAS_EXPIRED: return("certificate has expired"); - case V_ERR_CRL_HAS_EXPIRED: + case V_ERR_CRL_HAS_EXPIRED: return("CRL has expired"); - case V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD: + case V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD: return("format error in certificate's notBefore field"); - case V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD: + case V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD: return("format error in certificate's notAfter field"); - case V_ERR_ERROR_IN_CRL_LAST_UPDATE_FIELD: + case V_ERR_ERROR_IN_CRL_LAST_UPDATE_FIELD: return("format error in CRL's lastUpdate field"); - case V_ERR_ERROR_IN_CRL_NEXT_UPDATE_FIELD: + case V_ERR_ERROR_IN_CRL_NEXT_UPDATE_FIELD: return("format error in CRL's nextUpdate field"); - case V_ERR_OUT_OF_MEM: + case V_ERR_OUT_OF_MEM: return("out of memory"); - case V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT: + case V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT: return("self signed certificate"); - case V_ERR_SELF_SIGNED_CERT_IN_CHAIN: + case V_ERR_SELF_SIGNED_CERT_IN_CHAIN: return("self signed certificate in certificate chain"); - case V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY: + case V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY: return("unable to get local issuer certificate"); - case V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE: + case V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE: return("unable to verify the first certificate"); - case V_ERR_CERT_CHAIN_TOO_LONG: + case V_ERR_CERT_CHAIN_TOO_LONG: return("certificate chain too long"); - case V_ERR_CERT_REVOKED: + case V_ERR_CERT_REVOKED: return("certificate revoked"); - case V_ERR_INVALID_CA: + case V_ERR_INVALID_CA: return ("invalid CA certificate"); - case V_ERR_INVALID_NON_CA: - return ("invalid non-CA certificate (has CA markings)"); - case V_ERR_PATH_LENGTH_EXCEEDED: + case V_ERR_PATH_LENGTH_EXCEEDED: return ("path length constraint exceeded"); - case V_ERR_PROXY_PATH_LENGTH_EXCEEDED: - return("proxy path length constraint exceeded"); - case V_ERR_PROXY_CERTIFICATES_NOT_ALLOWED: - return("proxy cerificates not allowed, please set the appropriate flag"); - case V_ERR_INVALID_PURPOSE: + case V_ERR_INVALID_PURPOSE: return ("unsupported certificate purpose"); - case V_ERR_CERT_UNTRUSTED: + case V_ERR_CERT_UNTRUSTED: return ("certificate not trusted"); - case V_ERR_CERT_REJECTED: + case V_ERR_CERT_REJECTED: return ("certificate rejected"); - case V_ERR_APPLICATION_VERIFICATION: - return("application verification failure"); - case V_ERR_SUBJECT_ISSUER_MISMATCH: + case V_ERR_SUBJECT_ISSUER_MISMATCH: return("subject issuer mismatch"); - case V_ERR_AKID_SKID_MISMATCH: + case V_ERR_AKID_SKID_MISMATCH: return("authority and subject key identifier mismatch"); - case V_ERR_AKID_ISSUER_SERIAL_MISMATCH: + case V_ERR_AKID_ISSUER_SERIAL_MISMATCH: return("authority and issuer serial number mismatch"); - case V_ERR_KEYUSAGE_NO_CERTSIGN: + case V_ERR_KEYUSAGE_NO_CERTSIGN: return("key usage does not include certificate signing"); - case V_ERR_UNABLE_TO_GET_CRL_ISSUER: + case V_ERR_UNABLE_TO_GET_CRL_ISSUER: return("unable to get CRL issuer certificate"); - case V_ERR_UNHANDLED_CRITICAL_EXTENSION: + case V_ERR_UNHANDLED_CRITICAL_EXTENSION: return("unhandled critical extension"); - case V_ERR_KEYUSAGE_NO_CRL_SIGN: + case V_ERR_KEYUSAGE_NO_CRL_SIGN: return("key usage does not include CRL signing"); - case V_ERR_KEYUSAGE_NO_DIGITAL_SIGNATURE: - return("key usage does not include digital signature"); - case V_ERR_UNHANDLED_CRITICAL_CRL_EXTENSION: + case V_ERR_UNHANDLED_CRITICAL_CRL_EXTENSION: return("unhandled critical CRL extension"); - case V_ERR_INVALID_EXTENSION: + case V_ERR_INVALID_NON_CA: + return ("invalid non-CA certificate (has CA markings)"); + case V_ERR_PROXY_PATH_LENGTH_EXCEEDED: + return("proxy path length constraint exceeded"); + case V_ERR_KEYUSAGE_NO_DIGITAL_SIGNATURE: + return("key usage does not include digital signature"); + case V_ERR_PROXY_CERTIFICATES_NOT_ALLOWED: + return("proxy cerificates not allowed, please set the appropriate flag"); + case V_ERR_INVALID_EXTENSION: return("invalid or inconsistent certificate extension"); - case V_ERR_INVALID_POLICY_EXTENSION: + case V_ERR_INVALID_POLICY_EXTENSION: return("invalid or inconsistent certificate policy extension"); - case V_ERR_NO_EXPLICIT_POLICY: + case V_ERR_NO_EXPLICIT_POLICY: return("no explicit policy"); + case V_ERR_APPLICATION_VERIFICATION: + return("application verification failure"); default: return "error number " + error; } From e6cd6d5d78bd687b4793a1a3776b12043691c3cf Mon Sep 17 00:00:00 2001 From: kares Date: Thu, 14 Oct 2021 14:51:13 +0200 Subject: [PATCH 27/63] [fix] return + proper (OSSL 1.1.1) lookup_certs impl --- .../jruby/ext/openssl/x509store/Store.java | 6 ++ .../ext/openssl/x509store/StoreContext.java | 94 ++++++++----------- 2 files changed, 43 insertions(+), 57 deletions(-) diff --git a/src/main/java/org/jruby/ext/openssl/x509store/Store.java b/src/main/java/org/jruby/ext/openssl/x509store/Store.java index 9034164f..487a99f7 100644 --- a/src/main/java/org/jruby/ext/openssl/x509store/Store.java +++ b/src/main/java/org/jruby/ext/openssl/x509store/Store.java @@ -69,6 +69,10 @@ interface CertificateCRLFunction extends Function3 { } + interface LookupCerts { + List call(StoreContext ctx, Name name) throws Exception; + } + // @Deprecated int cache = 1; // not-used private static final X509Object[] NULL_OBJECTS = new X509Object[0]; @@ -90,6 +94,8 @@ interface CleanupFunction extends Function1 { } CertificateCRLFunction certificateCRL; CleanupFunction cleanup; + LookupCerts lookup_certs; // NOTE: for now always null here + private final List extraData; /** diff --git a/src/main/java/org/jruby/ext/openssl/x509store/StoreContext.java b/src/main/java/org/jruby/ext/openssl/x509store/StoreContext.java index e4c69fa2..460b2b05 100644 --- a/src/main/java/org/jruby/ext/openssl/x509store/StoreContext.java +++ b/src/main/java/org/jruby/ext/openssl/x509store/StoreContext.java @@ -87,6 +87,8 @@ interface CheckPolicyFunction extends Function1 {} CheckPolicyFunction checkPolicy; Store.CleanupFunction cleanup; + Store.LookupCerts lookup_certs; + public boolean isValid; private int num_untrusted; // lastUntrusted in the chain @@ -267,10 +269,18 @@ public int init(X509AuxCertificate cert, List chain) { } } + if (store != null && store.lookup_certs != null) { + this.lookup_certs = store.lookup_certs; + } else { + this.lookup_certs = new Store.LookupCerts() { + public List call(StoreContext ctx, Name name) throws Exception { + return ctx.get1_certs(name); + } + }; + } + // store->check_policy this.checkPolicy = StoreContext.check_policy; - // store->lookup_certs - // store->lookup_crls this.verifyParameter = new VerifyParameter(); @@ -623,61 +633,36 @@ public int getBySubject(int type, Name name, X509Object[] ret) throws Exception /* * STACK_OF(X509) *X509_STORE_CTX_get1_certs(X509_STORE_CTX *ctx, X509_NAME *nm) */ - List X509_STORE_CTX_get1_certs(final Name nm) { + List get1_certs(final Name nm) throws Exception { if (store == null) return null; -// X509_STORE_lock(store); -// idx = x509_object_idx_cnt(store->objs, X509_LU_X509, nm, &cnt); -// if (idx < 0) { -// /* -// * Nothing found in cache: do lookup to possibly add new objects to -// * cache -// */ -// X509_OBJECT *xobj = X509_OBJECT_new(); -// -// X509_STORE_unlock(store); -// -// if (xobj == NULL) -// return NULL; -// if (!X509_STORE_CTX_get_by_subject(ctx, X509_LU_X509, nm, xobj)) { -// X509_OBJECT_free(xobj); -// return NULL; -// } -// X509_OBJECT_free(xobj); -// X509_STORE_lock(store); -// idx = x509_object_idx_cnt(store->objs, X509_LU_X509, nm, &cnt); -// if (idx < 0) { -// X509_STORE_unlock(store); -// return NULL; -// } -// } - -// sk = sk_X509_new_null(); -// for (i = 0; i < cnt; i++, idx++) { -// obj = sk_X509_OBJECT_value(store->objs, idx); -// x = obj->data.x509; -// if (!X509_up_ref(x)) { -// X509_STORE_unlock(store); -// sk_X509_pop_free(sk, X509_free); -// return NULL; -// } -// if (!sk_X509_push(sk, x)) { -// X509_STORE_unlock(store); -// X509_free(x); -// sk_X509_pop_free(sk, X509_free); -// return NULL; -// } -// } -// X509_STORE_unlock(store); -// return sk; + // NOTE: very rough draft that resembles OpenSSL bits + + List sk = matchCachedCertObjectsFromStore(nm); + + if (sk.isEmpty()) { + /* + * Nothing found in cache: do lookup to possibly add new objects to cache + */ + boolean found = false; + for (Lookup lu : store.getCertificateMethods()) { + X509Object[] stmp = new X509Object[1]; + if (lu.bySubject(X509_LU_X509, nm, stmp) != 0) found = true; + } + if (!found) return sk; + } + + sk = matchCachedCertObjectsFromStore(nm); + return sk; + } + private List matchCachedCertObjectsFromStore(final Name name) { ArrayList sk = new ArrayList(); for (X509Object obj : store.getObjects()) { - if (obj.type() == X509_LU_X509 && obj.isName(nm)) { + if (obj.type() == X509_LU_X509 && obj.isName(name)) { sk.add(((Certificate) obj).cert); } } - return sk; } @@ -1774,22 +1759,17 @@ public int getCRLStack(X509CRL[] pcrl, Name name, List crls) throws Exc /* Given a certificate try and find an exact match in the store */ - private X509AuxCertificate lookup_cert_match(X509AuxCertificate x) { + private X509AuxCertificate lookup_cert_match(X509AuxCertificate x) throws Exception { /* Lookup all certs with matching subject name */ - List certs = lookup_certs(new Name(x.getSubjectX500Principal())); + List certs = lookup_certs.call(this, new Name(x.getSubjectX500Principal())); if (certs == null) return null; /* Look for exact match */ for (X509AuxCertificate xtmp : certs) { - if (xtmp.equals(x)) // !X509_cmp(xtmp, x) - break; + if (xtmp.equals(x)) return xtmp; } return null; // xtmp = null } - private List lookup_certs(final Name name) { - return X509_STORE_CTX_get1_certs(name); - } - /* * Inform the verify callback of an error. * If B is not NULL it is the error cert, otherwise use the chain cert at From 6d3fe277da124621637dd43ec2a075016bd21494 Mon Sep 17 00:00:00 2001 From: kares Date: Sat, 16 Oct 2021 18:52:18 +0200 Subject: [PATCH 28/63] [refactor] confusing naming --- .../java/org/jruby/ext/openssl/x509store/StoreContext.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/jruby/ext/openssl/x509store/StoreContext.java b/src/main/java/org/jruby/ext/openssl/x509store/StoreContext.java index 460b2b05..a0975991 100644 --- a/src/main/java/org/jruby/ext/openssl/x509store/StoreContext.java +++ b/src/main/java/org/jruby/ext/openssl/x509store/StoreContext.java @@ -208,10 +208,10 @@ public static X509AuxCertificate ensureAux(final X509Certificate input) { /** * c: X509_STORE_CTX_init */ - public int init(X509AuxCertificate cert, List chain) { + public int init(X509AuxCertificate cert, List untrusted_chain) { int ret = 1; this.certificate = cert; - this.untrusted = chain; + this.untrusted = untrusted_chain; this.crls = null; this.num_untrusted = 0; this.otherContext = null; From 8bbd8978bc0364ce04c0ac5582050a2430e51682 Mon Sep 17 00:00:00 2001 From: kares Date: Sat, 16 Oct 2021 19:00:40 +0200 Subject: [PATCH 29/63] DRAFT: 'minimal' legacy multi-path cert verification an attempt to retrofit verification to consider alt-chains --- .../ext/openssl/x509store/StoreContext.java | 209 +++++++++++++++--- 1 file changed, 180 insertions(+), 29 deletions(-) diff --git a/src/main/java/org/jruby/ext/openssl/x509store/StoreContext.java b/src/main/java/org/jruby/ext/openssl/x509store/StoreContext.java index a0975991..97ccac75 100644 --- a/src/main/java/org/jruby/ext/openssl/x509store/StoreContext.java +++ b/src/main/java/org/jruby/ext/openssl/x509store/StoreContext.java @@ -41,6 +41,7 @@ import java.util.HashSet; import java.util.LinkedList; import java.util.List; +import java.util.ListIterator; import java.util.Set; import org.bouncycastle.asn1.ASN1InputStream; @@ -137,7 +138,7 @@ public Object getApplicationData() { /** * c: X509_STORE_CTX_get1_issuer */ - int getFirstIssuer(final X509AuxCertificate[] issuers, final X509AuxCertificate x) throws Exception { + int getFirstIssuer(final X509AuxCertificate[] _issuer, final X509AuxCertificate x) throws Exception { final Name xn = new Name( x.getIssuerX500Principal() ); final X509Object[] s_obj = new X509Object[1]; int ok = store == null ? 0 : getBySubject(X509Utils.X509_LU_X509, xn, s_obj); @@ -151,33 +152,96 @@ else if ( ok != X509Utils.X509_LU_FAIL ) { } return 0; } - + /* If certificate matches all OK */ X509Object obj = s_obj[0]; if ( checkIssued.call(this, x, ((Certificate) obj).cert) != 0 ) { - issuers[0] = ((Certificate) obj).cert; - return 1; + X509AuxCertificate issuer = ((Certificate) obj).cert; + if (x509_check_cert_time(issuer, -1)) { + _issuer[0] = issuer; + return 1; + } } List objects = store.getObjects(); int idx = X509Object.indexBySubject(objects, X509Utils.X509_LU_X509, xn); if ( idx == -1 ) return 0; + int ret = 0; /* Look through all matching certificates for a suitable issuer */ for ( int i = idx; i < objects.size(); i++ ) { final X509Object pobj = objects.get(i); if ( pobj.type() != X509Utils.X509_LU_X509 ) { - return 0; + break; // return 0 } final X509AuxCertificate x509 = ((Certificate) pobj).cert; if ( ! xn.equalTo( x509.getSubjectX500Principal() ) ) { - return 0; + break; // return 0 } if ( checkIssued.call(this, x, x509) != 0 ) { - issuers[0] = x509; - return 1; + _issuer[0] = x509; + ret = 1; + /* + * If times check, exit with match, otherwise keep looking. + * Leave last match in issuer so we return nearest + * match if no certificate time is OK. + */ + if (x509_check_cert_time(x509, -1)) break; // return 1; } } - return 0; + return ret; + } + + // NOTE: not based on OpenSSL - self invented (till JOSSL 1.1.1 port) + private int getValidIssuers(final X509AuxCertificate x, final List _issuers) + throws Exception { + final Name xn = new Name( x.getIssuerX500Principal() ); + final X509Object[] s_obj = new X509Object[1]; + int ok = store == null ? 0 : getBySubject(X509Utils.X509_LU_X509, xn, s_obj); + if ( ok != X509Utils.X509_LU_X509 ) { + if ( ok == X509Utils.X509_LU_RETRY ) { + X509Error.addError(X509Utils.X509_R_SHOULD_RETRY); + return -1; + } + else if ( ok != X509Utils.X509_LU_FAIL ) { + return -1; + } + return 0; + } + int ret = 0; + /* If certificate matches all OK */ + X509Object obj = s_obj[0]; + if ( checkIssued.call(this, x, ((Certificate) obj).cert) != 0 ) { + X509AuxCertificate issuer = ((Certificate) obj).cert; + if (x509_check_cert_time(issuer, -1)) { + _issuers.add(issuer); + ret = 1; + } + } + + List objects = store.getObjects(); + + int idx = X509Object.indexBySubject(objects, X509Utils.X509_LU_X509, xn); + if ( idx == -1 ) return ret; + + /* Look through all matching certificates for a suitable issuer */ + for ( int i = idx; i < objects.size(); i++ ) { + final X509Object pobj = objects.get(i); + if ( pobj.type() != X509Utils.X509_LU_X509 ) { + continue; + } + final X509AuxCertificate x509 = ((Certificate) pobj).cert; + if ( ! xn.equalTo( x509.getSubjectX500Principal() ) ) { + continue; + } + + if ( checkIssued.call(this, x, x509) != 0 ) { + if (x509_check_cert_time(x509, -1)) { + _issuers.add(x509); + ret = 1; + } + } + } + return ret; } public static List ensureAux(final Collection input) { @@ -728,10 +792,27 @@ int verify_chain_legacy() throws Exception { X509AuxCertificate x, xtmp = null, chain_ss = null; int bad_chain = 0, depth, i, num; + System.out.println("" + getParam()); + // We use a temporary STACK so we can chop and hack at it LinkedList sktmp = untrusted != null ? new LinkedList<>(untrusted) : null; + if (untrusted != null) { + System.out.println("untrusted(" + untrusted.size() + "): " + untrusted.stream().map((c) -> c.getSubjectDN().toString() + "[" + c.getIssuerDN() + "]").collect(java.util.stream.Collectors.joining(" - "))); + + ListIterator iter = sktmp.listIterator(); + while (iter.hasNext()) { + X509AuxCertificate c = iter.next(); + if (!x509_check_cert_time(c, -1)) { + iter.remove(); + } + } + + System.out.println("sktmp(" + sktmp.size() + "): " + sktmp.stream().map((c) -> c.getSubjectDN().toString() + "[" + c.getIssuerDN() + "]").collect(java.util.stream.Collectors.joining(" - "))); + } + else System.out.println("untrusted: null"); + num = chain.size(); x = chain.get(num - 1); depth = verifyParameter.depth; @@ -741,7 +822,9 @@ int verify_chain_legacy() throws Exception { if ( checkIssued.call(this, x, x) != 0 ) break; if ( sktmp != null ) { - xtmp = findIssuer(sktmp, x); + xtmp = findIssuer(sktmp, x, true); + System.out.println(" findIssuer: " + (xtmp == null ? null : (xtmp.getSubjectDN() + "[" + xtmp.getIssuerDN() + "]"))); + if ( xtmp != null ) { chain.add(xtmp); sktmp.remove(xtmp); @@ -794,29 +877,69 @@ int verify_chain_legacy() throws Exception { x = chain.get(num-1); } } - // We now lookup certs from the certificate store - for(;;) { - // If we have enough, we break - if ( depth < num ) break; - //xn = new X509_NAME(x.getIssuerX500Principal()); - // If we are self signed, we break - if ( checkIssued.call(this, x, x) != 0 ) break; - X509AuxCertificate[] p_xtmp = new X509AuxCertificate[]{ xtmp }; - int ok = getIssuer.call(this, p_xtmp, x); - xtmp = p_xtmp[0]; + System.out.println(" getIssuer: " + getIssuer); - if ( ok < 0 ) return ok; - if ( ok == 0 ) break; + // We now lookup certs from the certificate store + // JOSSL specific re-invention with semi alternate chain search + if (checkIssued.call(this, x, x) == 0) { + final int[] p_num = new int[] { num }; + + if (getIssuer == getFirstIssuer) { + LinkedList xtmps = new LinkedList<>(); + int ok = getValidIssuers(x, xtmps); + if ( ok < 0 ) return ok; // error + if ( ok != 0 ) { // at least one issuer for given name + while (!xtmps.isEmpty()) { + chain.add(x = xtmps.removeFirst()); + p_num[0] = num + 1; + + ok = finishChain(x, depth, p_num); + if ( ok < 0 ) return ok; // error + if ( ok == 1 ) { + x = chain.get(chain.size() - 1); + if (x509_check_cert_time(x, -1)) break; + } + // we're going to retry thus reset chain back: + int added = p_num[0] - num; + while (added-- > 0) chain.remove(chain.size() - 1); + } + } + } else { + int ok = finishChain(x, depth, p_num); + if ( ok < 0 ) return ok; // error + } - x = xtmp; - chain.add(x); - num++; + if (p_num[0] != num) { + x = chain.get(chain.size() - 1); + } + num = p_num[0]; } + // We now lookup certs from the certificate store +// for(;;) { +// // If we have enough, we break +// if ( depth < num ) break; +// // If we are self signed, we break +// if ( checkIssued.call(this, x, x) != 0 ) break; +// +// X509AuxCertificate[] p_xtmp = new X509AuxCertificate[]{ xtmp }; +// int ok = getIssuer.call(this, p_xtmp, x); +// xtmp = p_xtmp[0]; +// +// if ( ok < 0 ) return ok; +// if ( ok == 0 ) break; +// +// x = xtmp; +// +// System.out.println(" chain.add next: " + (xtmp == null ? null : (xtmp.getSubjectDN() + "[" + xtmp.getIssuerDN() + "]"))); +// +// chain.add(x); +// num++; +// } + /* we now have our chain, lets check it... */ - //xn = new X509_NAME(x.getIssuerX500Principal()); /* Is last certificate looked up self signed? */ if ( checkIssued.call(this, x, x) == 0 ) { if ( chain_ss == null || checkIssued.call(this, x, chain_ss) == 0 ) { @@ -871,6 +994,31 @@ int verify_chain_legacy() throws Exception { return ok; } + // JOSSL specific re-invention with semi alternate chain search + private int finishChain(X509AuxCertificate x, final int depth, final int[] _num) + throws Exception { + X509AuxCertificate[] p_xtmp = new X509AuxCertificate[] { null }; + int num = _num[0]; + for(;;) { + // If we have enough, we break + if ( depth < num ) break; + // If we are self signed, we break + if ( checkIssued.call(this, x, x) != 0 ) break; + + int ok = getIssuer.call(this, p_xtmp, x); + if ( ok < 0 ) return ok; // error + if ( ok == 0 ) return 0; // no issuer for given name + + x = p_xtmp[0]; + + chain.add(x); + num++; + } + + _num[0] = num; + return 1; + } + /* @ @note: based OpenSSL 1.1.1 * @@ -1196,10 +1344,13 @@ int build_chain() throws Exception { } @Deprecated // legacy find_issuer - public X509AuxCertificate findIssuer(final List certs, final X509AuxCertificate cert) throws Exception { + public X509AuxCertificate findIssuer(final List certs, + final X509AuxCertificate cert, final boolean check_time) throws Exception { for ( X509AuxCertificate issuer : certs ) { if ( checkIssued.call(this, cert, issuer) != 0 ) { - return issuer; + + if (!check_time || x509_check_cert_time(issuer, -1)) return issuer; + //return issuer; } } return null; @@ -1797,7 +1948,7 @@ public int call(StoreContext context, X509AuxCertificate[] issuer, X509AuxCertif */ final static Store.GetIssuerFunction getIssuerStack = new Store.GetIssuerFunction() { public int call(StoreContext context, X509AuxCertificate[] issuer, X509AuxCertificate x) throws Exception { - issuer[0] = context.findIssuer(context.otherContext, x); + issuer[0] = context.findIssuer(context.otherContext, x, false); if ( issuer[0] != null ) { return 1; } else { From be9858e59a9bcaf0615f1377cd847cb98b7e9f95 Mon Sep 17 00:00:00 2001 From: kares Date: Sun, 17 Oct 2021 13:08:11 +0200 Subject: [PATCH 30/63] [fix] SIGHT the usual < > copy pasta mess! --- .../org/jruby/ext/openssl/x509store/StoreContext.java | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/jruby/ext/openssl/x509store/StoreContext.java b/src/main/java/org/jruby/ext/openssl/x509store/StoreContext.java index 97ccac75..86b6915f 100644 --- a/src/main/java/org/jruby/ext/openssl/x509store/StoreContext.java +++ b/src/main/java/org/jruby/ext/openssl/x509store/StoreContext.java @@ -1808,7 +1808,9 @@ boolean x509_check_cert_time(X509AuxCertificate x, final int depth) throws Excep } int i = x.getNotBefore().compareTo(pTime); - if (i >= 0 && depth < 0) return false; + if (i >= 0 && depth < 0) { + return false; + } if (i == 0 && verify_cb_cert(x, depth, V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD) == 0) { return false; } @@ -1817,7 +1819,9 @@ boolean x509_check_cert_time(X509AuxCertificate x, final int depth) throws Excep } i = x.getNotAfter().compareTo(pTime); - if (i >= 0 && depth < 0) return false; + if (i <= 0 && depth < 0) { + return false; + } if (i == 0 && verify_cb_cert(x, depth, V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD) == 0) { return false; } From 8bb82ade04b1c6d355885bcba048e5e4ebaad0f4 Mon Sep 17 00:00:00 2001 From: kares Date: Mon, 18 Oct 2021 13:49:46 +0200 Subject: [PATCH 31/63] Revert: DRAFT: 'minimal' legacy multi-path cert verification manually undo legacy changes ... --- .../ext/openssl/x509store/StoreContext.java | 98 +++---------------- 1 file changed, 16 insertions(+), 82 deletions(-) diff --git a/src/main/java/org/jruby/ext/openssl/x509store/StoreContext.java b/src/main/java/org/jruby/ext/openssl/x509store/StoreContext.java index 86b6915f..79df93aa 100644 --- a/src/main/java/org/jruby/ext/openssl/x509store/StoreContext.java +++ b/src/main/java/org/jruby/ext/openssl/x509store/StoreContext.java @@ -823,8 +823,6 @@ int verify_chain_legacy() throws Exception { if ( sktmp != null ) { xtmp = findIssuer(sktmp, x, true); - System.out.println(" findIssuer: " + (xtmp == null ? null : (xtmp.getSubjectDN() + "[" + xtmp.getIssuerDN() + "]"))); - if ( xtmp != null ) { chain.add(xtmp); sktmp.remove(xtmp); @@ -878,65 +876,26 @@ int verify_chain_legacy() throws Exception { } } - System.out.println(" getIssuer: " + getIssuer); - // We now lookup certs from the certificate store - // JOSSL specific re-invention with semi alternate chain search - if (checkIssued.call(this, x, x) == 0) { - final int[] p_num = new int[] { num }; - - if (getIssuer == getFirstIssuer) { - LinkedList xtmps = new LinkedList<>(); - int ok = getValidIssuers(x, xtmps); - if ( ok < 0 ) return ok; // error - if ( ok != 0 ) { // at least one issuer for given name - while (!xtmps.isEmpty()) { - chain.add(x = xtmps.removeFirst()); - p_num[0] = num + 1; - - ok = finishChain(x, depth, p_num); - if ( ok < 0 ) return ok; // error - if ( ok == 1 ) { - x = chain.get(chain.size() - 1); - if (x509_check_cert_time(x, -1)) break; - } - // we're going to retry thus reset chain back: - int added = p_num[0] - num; - while (added-- > 0) chain.remove(chain.size() - 1); - } - } - } else { - int ok = finishChain(x, depth, p_num); - if ( ok < 0 ) return ok; // error - } + for(;;) { + // If we have enough, we break + if ( depth < num ) break; + // If we are self signed, we break + if ( checkIssued.call(this, x, x) != 0 ) break; - if (p_num[0] != num) { - x = chain.get(chain.size() - 1); - } - num = p_num[0]; + X509AuxCertificate[] p_xtmp = new X509AuxCertificate[]{ xtmp }; + int ok = getIssuer.call(this, p_xtmp, x); + xtmp = p_xtmp[0]; + + if ( ok < 0 ) return ok; + if ( ok == 0 ) break; + + x = xtmp; + + chain.add(x); + num++; } - // We now lookup certs from the certificate store -// for(;;) { -// // If we have enough, we break -// if ( depth < num ) break; -// // If we are self signed, we break -// if ( checkIssued.call(this, x, x) != 0 ) break; -// -// X509AuxCertificate[] p_xtmp = new X509AuxCertificate[]{ xtmp }; -// int ok = getIssuer.call(this, p_xtmp, x); -// xtmp = p_xtmp[0]; -// -// if ( ok < 0 ) return ok; -// if ( ok == 0 ) break; -// -// x = xtmp; -// -// System.out.println(" chain.add next: " + (xtmp == null ? null : (xtmp.getSubjectDN() + "[" + xtmp.getIssuerDN() + "]"))); -// -// chain.add(x); -// num++; -// } /* we now have our chain, lets check it... */ @@ -994,31 +953,6 @@ int verify_chain_legacy() throws Exception { return ok; } - // JOSSL specific re-invention with semi alternate chain search - private int finishChain(X509AuxCertificate x, final int depth, final int[] _num) - throws Exception { - X509AuxCertificate[] p_xtmp = new X509AuxCertificate[] { null }; - int num = _num[0]; - for(;;) { - // If we have enough, we break - if ( depth < num ) break; - // If we are self signed, we break - if ( checkIssued.call(this, x, x) != 0 ) break; - - int ok = getIssuer.call(this, p_xtmp, x); - if ( ok < 0 ) return ok; // error - if ( ok == 0 ) return 0; // no issuer for given name - - x = p_xtmp[0]; - - chain.add(x); - num++; - } - - _num[0] = num; - return 1; - } - /* @ @note: based OpenSSL 1.1.1 * From 567b03b8f6a9c388a23509e168488ad2d21a8951 Mon Sep 17 00:00:00 2001 From: kares Date: Mon, 18 Oct 2021 13:51:49 +0200 Subject: [PATCH 32/63] revert legacy changes (+ out prints) fully --- .../ext/openssl/x509store/StoreContext.java | 18 ------------------ 1 file changed, 18 deletions(-) diff --git a/src/main/java/org/jruby/ext/openssl/x509store/StoreContext.java b/src/main/java/org/jruby/ext/openssl/x509store/StoreContext.java index 79df93aa..001cfff7 100644 --- a/src/main/java/org/jruby/ext/openssl/x509store/StoreContext.java +++ b/src/main/java/org/jruby/ext/openssl/x509store/StoreContext.java @@ -792,27 +792,10 @@ int verify_chain_legacy() throws Exception { X509AuxCertificate x, xtmp = null, chain_ss = null; int bad_chain = 0, depth, i, num; - System.out.println("" + getParam()); - // We use a temporary STACK so we can chop and hack at it LinkedList sktmp = untrusted != null ? new LinkedList<>(untrusted) : null; - if (untrusted != null) { - System.out.println("untrusted(" + untrusted.size() + "): " + untrusted.stream().map((c) -> c.getSubjectDN().toString() + "[" + c.getIssuerDN() + "]").collect(java.util.stream.Collectors.joining(" - "))); - - ListIterator iter = sktmp.listIterator(); - while (iter.hasNext()) { - X509AuxCertificate c = iter.next(); - if (!x509_check_cert_time(c, -1)) { - iter.remove(); - } - } - - System.out.println("sktmp(" + sktmp.size() + "): " + sktmp.stream().map((c) -> c.getSubjectDN().toString() + "[" + c.getIssuerDN() + "]").collect(java.util.stream.Collectors.joining(" - "))); - } - else System.out.println("untrusted: null"); - num = chain.size(); x = chain.get(num - 1); depth = verifyParameter.depth; @@ -896,7 +879,6 @@ int verify_chain_legacy() throws Exception { num++; } - /* we now have our chain, lets check it... */ /* Is last certificate looked up self signed? */ From 622758086dc6c349f7f8cb13e3b6b9207e396a02 Mon Sep 17 00:00:00 2001 From: kares Date: Tue, 19 Oct 2021 10:38:04 +0200 Subject: [PATCH 33/63] [refactor] review X509_STORE_CTX_purpose_inherit --- .../ext/openssl/x509store/StoreContext.java | 54 ++++++++++--------- 1 file changed, 30 insertions(+), 24 deletions(-) diff --git a/src/main/java/org/jruby/ext/openssl/x509store/StoreContext.java b/src/main/java/org/jruby/ext/openssl/x509store/StoreContext.java index 001cfff7..d92b1eaa 100644 --- a/src/main/java/org/jruby/ext/openssl/x509store/StoreContext.java +++ b/src/main/java/org/jruby/ext/openssl/x509store/StoreContext.java @@ -488,14 +488,16 @@ public void setCRLs(List sk) { } /** - * c: X509_STORE_CTX_set_purpose + * int X509_STORE_CTX_set_purpose(X509_STORE_CTX *ctx, int purpose) + * @return 0 || 1 */ public int setPurpose(int purpose) { return purposeInherit(0, purpose, 0); } /** - * c: X509_STORE_CTX_set_trust + * int X509_STORE_CTX_set_trust(X509_STORE_CTX *ctx, int trust) + * @return 0 || 1 */ public int setTrust(int trust) { return purposeInherit(0, 0, trust); @@ -569,46 +571,50 @@ public int loadVerifyLocations(Ruby runtime, String CAfile, String CApath) { } } */ - /** - * c: X509_STORE_CTX_purpose_inherit + /* + * int X509_STORE_CTX_purpose_inherit(X509_STORE_CTX *ctx, int def_purpose, + * int purpose, int trust) */ - public int purposeInherit(int defaultPurpose,int purpose, int trust) { + private int purposeInherit(final int def_purpose, int purpose, int trust) { int idx; - if(purpose == 0) { - purpose = defaultPurpose; - } - if(purpose != 0) { - idx = Purpose.getByID(purpose); - if(idx == -1) { + /* If purpose not set use default */ + if (purpose == 0) { + purpose = def_purpose; + } + /* If we have a purpose then check it is valid */ + if (purpose != 0) { + idx = Purpose.getByID(purpose); // X509_PURPOSE_get_by_id + if (idx == -1) { X509Error.addError(X509Utils.X509_R_UNKNOWN_PURPOSE_ID); return 0; } - Purpose ptmp = Purpose.getFirst(idx); - if(ptmp.trust == X509Utils.X509_TRUST_DEFAULT) { - idx = Purpose.getByID(defaultPurpose); - if(idx == -1) { + Purpose ptmp = Purpose.getFirst(idx); // X509_PURPOSE_get0 + if (ptmp.trust == X509Utils.X509_TRUST_DEFAULT) { + idx = Purpose.getByID(def_purpose); + if (idx == -1) { X509Error.addError(X509Utils.X509_R_UNKNOWN_PURPOSE_ID); return 0; } - ptmp = Purpose.getFirst(idx); + ptmp = Purpose.getFirst(idx); // X509_PURPOSE_get0 } - if(trust == 0) { + /* If trust not set then get from purpose default */ + if (trust == 0) { trust = ptmp.trust; } } - if(trust != 0) { - idx = Trust.getByID(trust); - if(idx == -1) { + if (trust != 0) { + idx = Trust.getByID(trust); // X509_TRUST_get_by_id + if (idx == -1) { X509Error.addError(X509Utils.X509_R_UNKNOWN_TRUST_ID); return 0; } } - if(purpose != 0 && verifyParameter.purpose == 0) { - verifyParameter.purpose = purpose; + if (purpose != 0 && getParam().purpose == 0) { + getParam().purpose = purpose; } - if(trust != 0 && verifyParameter.trust == 0) { - verifyParameter.trust = trust; + if (trust != 0 && getParam().trust == 0) { + getParam().trust = trust; } return 1; } From 8d7f1d3b337a1f4c7e378ca4818b56bd60bb77c0 Mon Sep 17 00:00:00 2001 From: kares Date: Tue, 19 Oct 2021 10:55:35 +0200 Subject: [PATCH 34/63] [refactor] review and port-over trust checking --- .../ext/openssl/x509store/StoreContext.java | 6 +- .../jruby/ext/openssl/x509store/Trust.java | 130 +++++++++++++----- .../ext/openssl/x509store/X509Utils.java | 2 +- 3 files changed, 102 insertions(+), 36 deletions(-) diff --git a/src/main/java/org/jruby/ext/openssl/x509store/StoreContext.java b/src/main/java/org/jruby/ext/openssl/x509store/StoreContext.java index d92b1eaa..58e0295c 100644 --- a/src/main/java/org/jruby/ext/openssl/x509store/StoreContext.java +++ b/src/main/java/org/jruby/ext/openssl/x509store/StoreContext.java @@ -1621,6 +1621,7 @@ private boolean cert_self_signed(X509AuxCertificate x) throws CertificateExcepti return false; } + // NOTE: does not execute by default due: if ( verifyParameter.trust > 0 ) ... @Deprecated // legacy check_trust private int checkTrust() throws Exception { int i,ok; @@ -1628,8 +1629,9 @@ private int checkTrust() throws Exception { i = chain.size()-1; x = chain.get(i); ok = Trust.checkTrust(x, verifyParameter.trust, 0); + if ( ok == X509Utils.X509_TRUST_TRUSTED ) { - return 1; + return 1; // X509_TRUST_TRUSTED } errorDepth = 1; currentCertificate = x; @@ -1644,7 +1646,7 @@ private int checkTrust() throws Exception { /* * x509_vfy.c: check_trust(X509_STORE_CTX *ctx, int num_untrusted) */ - private int check_trust(int num_untrusted) throws Exception { + private int check_trust(final int num_untrusted) throws Exception { int i; final int num = chain.size(); int trust; diff --git a/src/main/java/org/jruby/ext/openssl/x509store/Trust.java b/src/main/java/org/jruby/ext/openssl/x509store/Trust.java index 4c19017c..054b375c 100644 --- a/src/main/java/org/jruby/ext/openssl/x509store/Trust.java +++ b/src/main/java/org/jruby/ext/openssl/x509store/Trust.java @@ -27,10 +27,15 @@ ***** END LICENSE BLOCK *****/ package org.jruby.ext.openssl.x509store; +import org.jruby.ext.openssl.impl.ASN1Registry; + +import java.io.IOException; import java.security.cert.CertificateException; import java.util.ArrayList; import java.util.List; +import static org.jruby.ext.openssl.x509store.X509Utils.*; + /** * c: X509_TRUST * @@ -38,7 +43,9 @@ */ public class Trust { - static interface Checker extends Function3 {} + interface Checker { + int call(T arg0, X509AuxCertificate x, int flags) throws Exception; + } public int trust; public int flags; @@ -70,18 +77,24 @@ public static Checker setDefault(Checker trust) { private final static List trustable = new ArrayList(); + private static final String OID_anyExtendedKeyUsage = ASN1Registry.nid2oid(ASN1Registry.NID_anyExtendedKeyUsage); + /** * c: X509_check_trust */ public static int checkTrust(X509AuxCertificate x, int id, int flags) throws Exception { - if ( id == -1 ) return 1; + /* We get this as a default value */ + if (id == X509_TRUST_DEFAULT) { + // return obj_trust(NID_anyExtendedKeyUsage, x, flags | X509_TRUST_DO_SS_COMPAT); + return objTrust.call(OID_anyExtendedKeyUsage, x, flags | X509_TRUST_DO_SS_COMPAT); + } int idx = getByID(id); if (idx == -1) { - return defaultTrust.call(Integer.toString(id), x, Integer.valueOf(flags)); + return defaultTrust.call(Integer.toString(id), x, flags); } - Trust pt = getFirst(idx); - return pt.checkTrust.call(pt, x, Integer.valueOf(flags)); + Trust pt = get0(idx); + return pt.checkTrust.call(pt, x, flags); } /** @@ -94,11 +107,11 @@ public static int getCount() { /** * c: X509_TRUST_get0 */ - public static Trust getFirst(int idx) { - if(idx < 0) { + private static Trust get0(int idx) { + if (idx < 0) { return null; } - if(idx < trstandard.length) { + if (idx < trstandard.length) { return trstandard[idx]; } return trustable.get(idx - trstandard.length); @@ -145,7 +158,7 @@ static int add(int id, int flags, Checker ck, String name, String arg1, O trtmp = new Trust(); trtmp.flags = X509Utils.X509_TRUST_DYNAMIC; } else { - trtmp = getFirst(idx); + trtmp = get0(idx); } trtmp.name = name; trtmp.flags &= X509Utils.X509_TRUST_DYNAMIC; @@ -191,15 +204,27 @@ public int getTrust() { /** * c: trust_compat */ + private static int trust_compat(X509AuxCertificate x, int flags) + throws CertificateException, IOException { + /* Call for side-effect of computing hash and caching extensions */ + if (Purpose.checkPurpose(x, -1, 0) != 1) // X509_check_purpose + return X509_TRUST_UNTRUSTED; + // TODO flip to using EXFLAG_SS once legacy (verify) compatibility is dropped + //if ((flags & X509_TRUST_NO_SS_COMPAT) == 0 && (x.getExFlags() & EXFLAG_SS) != 0) + if ((flags & X509_TRUST_NO_SS_COMPAT) == 0 && + x.getIssuerX500Principal().equals( x.getSubjectX500Principal() )) // self signed + return X509_TRUST_TRUSTED; + return X509_TRUST_UNTRUSTED; + } + final static Checker trustCompatibe = new Checker() { - public int call(final Trust trust, - final X509AuxCertificate x, final Integer flags) throws CertificateException { - Purpose.checkPurpose(x,-1,0); - if ( x.getIssuerX500Principal().equals( x.getSubjectX500Principal() ) ) { // self signed - return X509Utils.X509_TRUST_TRUSTED; - } else { - return X509Utils.X509_TRUST_UNTRUSTED; - } + public int call(Trust trust, X509AuxCertificate x, int flags) throws Exception { + return trust_compat(x, flags); + } + + @Override + public String toString() { + return "trustCompatibe"; // only for debugging } }; @@ -207,50 +232,89 @@ public int call(final Trust trust, * c: trust_1oidany */ final static Checker trust1OIDAny = new Checker() { - public int call(final Trust trust, - final X509AuxCertificate x, final Integer flags) throws Exception { + public int call(Trust trust, X509AuxCertificate x, int flags) throws Exception { final X509Aux aux = x.aux; if ( aux != null && ( aux.trust.size() > 0 || aux.reject.size() > 0 ) ) { return objTrust.call(trust.arg1, x, flags); } return trustCompatibe.call(trust, x, flags); } + + @Override + public String toString() { + return "trust1OIDAny"; // only for debugging + } }; /** * c: trust_1oid */ final static Checker trust1OID = new Checker() { - public int call(final Trust trust, - final X509AuxCertificate x, final Integer flags) throws Exception { + public int call(Trust trust, X509AuxCertificate x, int flags) throws Exception { if ( x.aux != null ) { return objTrust.call(trust.arg1, x, flags); } return X509Utils.X509_TRUST_UNTRUSTED; } + + @Override + public String toString() { + return "trust1OID"; // only for debugging + } }; /** * c: obj_trust */ final static Checker objTrust = new Checker() { - public int call(final String id, - final X509AuxCertificate x, final Integer flags) { + public int call(final String id, X509AuxCertificate x, int flags) throws Exception { final X509Aux aux = x.aux; - if ( aux == null ) { - return X509Utils.X509_TRUST_UNTRUSTED; - } - for ( String rejectId : aux.reject ) { - if ( rejectId.equals(id) ) { - return X509Utils.X509_TRUST_REJECTED; + + if ( aux != null && aux.reject != null ) { + for ( String oid : aux.reject ) { + if (oid.equals(id) || (oid.equals(OID_anyExtendedKeyUsage) && + (flags & X509_TRUST_OK_ANY_EKU) != 0)) { + return X509_TRUST_REJECTED; + } } } - for ( String trustId : aux.trust ) { - if ( trustId.equals(id) ) { - return X509Utils.X509_TRUST_TRUSTED; + + if ( aux != null && aux.trust != null ) { + for ( String oid : aux.trust ) { + if (oid.equals(id) || (oid.equals(OID_anyExtendedKeyUsage) && + (flags & X509_TRUST_OK_ANY_EKU) != 0)) { + return X509_TRUST_TRUSTED; + } } + /* + * Reject when explicit trust EKU are set and none match. + * + * Returning untrusted is enough for for full chains that end in + * self-signed roots, because when explicit trust is specified it + * suppresses the default blanket trust of self-signed objects. + * + * But for partial chains, this is not enough, because absent a similar + * trust-self-signed policy, non matching EKUs are indistinguishable + * from lack of EKU constraints. + * + * Therefore, failure to match any trusted purpose must trigger an + * explicit reject. + */ + return X509_TRUST_REJECTED; } - return X509Utils.X509_TRUST_UNTRUSTED; + + if ((flags & X509_TRUST_DO_SS_COMPAT) == 0) + return X509_TRUST_UNTRUSTED; + + /* + * Not rejected, and there is no list of accepted uses, try compat. + */ + return trust_compat(x, flags); + } + + @Override + public String toString() { + return "objTrust"; // only for debugging } }; diff --git a/src/main/java/org/jruby/ext/openssl/x509store/X509Utils.java b/src/main/java/org/jruby/ext/openssl/x509store/X509Utils.java index 41a77d2d..ce2352a4 100644 --- a/src/main/java/org/jruby/ext/openssl/x509store/X509Utils.java +++ b/src/main/java/org/jruby/ext/openssl/x509store/X509Utils.java @@ -519,7 +519,7 @@ else if (maybeCertFile != null && new File(maybeCertFile).exists()) { public static final int X509_PURPOSE_MIN = 1; public static final int X509_PURPOSE_MAX = 8; - public static final int X509_TRUST_DEFAULT = -1; + public static final int X509_TRUST_DEFAULT = 0; /* Only valid in purpose settings */ public static final int X509_TRUST_COMPAT = 1; public static final int X509_TRUST_SSL_CLIENT = 2; From 6854f84bbd5391c92cfbecc17bfc2aad608b5231 Mon Sep 17 00:00:00 2001 From: kares Date: Tue, 19 Oct 2021 12:04:20 +0200 Subject: [PATCH 35/63] aligh X509_STORE_CTX_init (set trust) --- .../jruby/ext/openssl/x509store/Store.java | 4 +- .../ext/openssl/x509store/StoreContext.java | 39 ++++++++++++------- .../openssl/x509store/VerifyParameter.java | 16 ++++---- 3 files changed, 35 insertions(+), 24 deletions(-) diff --git a/src/main/java/org/jruby/ext/openssl/x509store/Store.java b/src/main/java/org/jruby/ext/openssl/x509store/Store.java index 487a99f7..a0cf24b1 100644 --- a/src/main/java/org/jruby/ext/openssl/x509store/Store.java +++ b/src/main/java/org/jruby/ext/openssl/x509store/Store.java @@ -200,8 +200,8 @@ public int setTrust(int trust) { /** * c: X509_STORE_set1_param */ - public int setParam(VerifyParameter param) { - return verifyParameter.set(param); + public void setParam(VerifyParameter param) { + verifyParameter.set(param); } /** diff --git a/src/main/java/org/jruby/ext/openssl/x509store/StoreContext.java b/src/main/java/org/jruby/ext/openssl/x509store/StoreContext.java index 58e0295c..a59eb99a 100644 --- a/src/main/java/org/jruby/ext/openssl/x509store/StoreContext.java +++ b/src/main/java/org/jruby/ext/openssl/x509store/StoreContext.java @@ -270,10 +270,15 @@ public static X509AuxCertificate ensureAux(final X509Certificate input) { } /** - * c: X509_STORE_CTX_init + * int X509_STORE_CTX_init(X509_STORE_CTX *ctx, X509_STORE *store, X509 *cert, + * STACK_OF(X509) *chain) + * + * @param cert the certificate (to be verified) + * @param untrusted_chain the (untrusted) chain of certs returned by the server + * @return 1 */ public int init(X509AuxCertificate cert, List untrusted_chain) { - int ret = 1; + // int ret = 1; this.certificate = cert; this.untrusted = untrusted_chain; this.crls = null; @@ -349,21 +354,27 @@ public List call(StoreContext ctx, Name name) throws Excepti this.verifyParameter = new VerifyParameter(); if ( store != null ) { - ret = verifyParameter.inherit(store.verifyParameter); + verifyParameter.inherit(store.verifyParameter); } else { - verifyParameter.flags |= X509Utils.X509_VP_FLAG_DEFAULT | X509Utils.X509_VP_FLAG_ONCE; + verifyParameter.inheritFlags |= X509_VP_FLAG_DEFAULT | X509_VP_FLAG_ONCE; } - if ( ret != 0 ) { - ret = verifyParameter.inherit(VerifyParameter.lookup("default")); - } + verifyParameter.inherit(VerifyParameter.lookup("default")); - if ( ret == 0 ) { - X509Error.addError(X509Utils.ERR_R_MALLOC_FAILURE); - return 0; + /* + * XXX: For now, continue to inherit trust from VPM, but infer from the + * purpose if this still yields the default value. + */ + if (verifyParameter.trust == X509_TRUST_DEFAULT) { + int idx = Purpose.getByID(verifyParameter.purpose); + Purpose xp = Purpose.getFirst(idx); + + if (xp != null) { + verifyParameter.trust = xp.trust; // X509_PURPOSE_get_trust + } } - // getExtraData(); + // getExtraData(); // CRYPTO_new_ex_data return 1; } @@ -671,10 +682,10 @@ public void setParam(VerifyParameter param) { /** * c: X509_STORE_CTX_set_default */ - public int setDefault(String name) { + public void setDefault(String name) { VerifyParameter p = VerifyParameter.lookup(name); - if ( p == null ) return 0; - return verifyParameter.inherit(p); + if ( p == null ) return; // return 0 + verifyParameter.inherit(p); // return 1 } /* diff --git a/src/main/java/org/jruby/ext/openssl/x509store/VerifyParameter.java b/src/main/java/org/jruby/ext/openssl/x509store/VerifyParameter.java index 0708e3b4..f176f5e7 100644 --- a/src/main/java/org/jruby/ext/openssl/x509store/VerifyParameter.java +++ b/src/main/java/org/jruby/ext/openssl/x509store/VerifyParameter.java @@ -88,12 +88,12 @@ public void free() { /** * c: X509_VERIFY_PARAM_inherit */ - public int inherit(VerifyParameter src) { + public void inherit(VerifyParameter src) { long inh_flags; boolean to_d, to_o; - if(src == null) { - return 1; + if (src == null) { + return; } @@ -102,7 +102,7 @@ public int inherit(VerifyParameter src) { this.inheritFlags = 0; } if((inh_flags & X509Utils.X509_VP_FLAG_LOCKED) != 0) { - return 1; + return; } to_d = ((inh_flags & X509Utils.X509_VP_FLAG_DEFAULT) != 0); to_o = ((inh_flags & X509Utils.X509_VP_FLAG_OVERWRITE) != 0); @@ -128,18 +128,18 @@ public int inherit(VerifyParameter src) { this.flags |= src.flags; - if(to_o || ((src.policies != null && (to_d || this.policies == null)))) { + if (to_o || ((src.policies != null && (to_d || this.policies == null)))) { setPolicies(src.policies); } - return 1; + return; } /** * c: X509_VERIFY_PARAM_set1 */ - public int set(VerifyParameter from) { + void set(VerifyParameter from) { inheritFlags |= X509Utils.X509_VP_FLAG_DEFAULT; - return inherit(from); + inherit(from); } /** From 983ef9489fbc240c558a608cb5426f2952dbcbdd Mon Sep 17 00:00:00 2001 From: kares Date: Tue, 19 Oct 2021 17:35:28 +0200 Subject: [PATCH 36/63] [fix] revert 'smart' certificate addition to store need to match OpenSSL here for verification to behave the same --- .../jruby/ext/openssl/x509store/Store.java | 62 ++++++------------- 1 file changed, 20 insertions(+), 42 deletions(-) diff --git a/src/main/java/org/jruby/ext/openssl/x509store/Store.java b/src/main/java/org/jruby/ext/openssl/x509store/Store.java index a0cf24b1..606a6acb 100644 --- a/src/main/java/org/jruby/ext/openssl/x509store/Store.java +++ b/src/main/java/org/jruby/ext/openssl/x509store/Store.java @@ -234,20 +234,20 @@ private static Lookup findLookupMethod(final Lookup[] lookups, final LookupMetho } /** - * c: X509_STORE_add_cert + * int X509_STORE_add_cert(X509_STORE *ctx, X509 *x) */ public int addCertificate(final X509Certificate cert) { if ( cert == null ) return 0; - final Certificate certObj = new Certificate(StoreContext.ensureAux(cert)); + final Certificate obj = new Certificate(StoreContext.ensureAux(cert)); - final X509Object[] objects = this.objects; - if ( matchedObject(objects, certObj) ) { - X509Error.addError(X509_R_CERT_ALREADY_IN_HASH_TABLE); - return 0; + synchronized (this) { + final X509Object[] objects = this.objects; + if ( matchedObject(objects, obj) ) { + return 1; + } + return addObject(obj); // 1 } - - return addObject(certObj, objects.length); } /** @@ -256,15 +256,15 @@ public int addCertificate(final X509Certificate cert) { public int addCRL(final java.security.cert.CRL crl) { if ( crl == null ) return 0; - final CRL crlObj = new CRL(crl); + final CRL obj = new CRL(crl); - final X509Object[] objects = this.objects; - if ( matchedObject(objects, crlObj) ) { - X509Error.addError(X509_R_CERT_ALREADY_IN_HASH_TABLE); - return 0; + synchronized (this) { + final X509Object[] objects = this.objects; + if ( matchedObject(objects, obj) ) { + return 1; + } + return addObject(obj); // 1 } - - return addObject(crlObj, objects.length); } private static boolean matchedObject(final X509Object[] objects, final X509Object xObject) { @@ -274,34 +274,12 @@ private static boolean matchedObject(final X509Object[] objects, final X509Objec return false; } - private synchronized int addObject(final X509Object xObject, final int prevLength) { - final int length = objects.length; - if ( length != prevLength ) { // something added concurrently - if ( matchedObject(objects, xObject) ) { - X509Error.addError(X509_R_CERT_ALREADY_IN_HASH_TABLE); - return 0; - } - } - X509Object[] newObjects = new X509Object[length + 1]; - - int idx = length; - if (xObject instanceof Certificate) { - final X500Principal p1 = ((Certificate) xObject).cert.getIssuerX500Principal(); - final Name n1 = new Name(p1); - - for (idx = 0; idx < objects.length; idx++) { - X509Object xMember = objects[idx]; - if (xMember instanceof Certificate) { - X500Principal p2 = ((Certificate) xMember).cert.getIssuerX500Principal(); - if (n1.equalTo(p2)) break; - } - } - } + private int addObject(final X509Object xObject) { + final int len = this.objects.length; - System.arraycopy(objects, 0, newObjects, 0, idx); - System.arraycopy(objects, idx, newObjects, idx + 1, length-idx); - newObjects[idx] = xObject; - objects = newObjects; + X509Object[] objects = Arrays.copyOf(this.objects, len + 1); + objects[len] = xObject; + this.objects = objects; return 1; } From 196b44c6d130581e1d4ed9cab6cb14a5ba919e1e Mon Sep 17 00:00:00 2001 From: kares Date: Tue, 19 Oct 2021 17:46:23 +0200 Subject: [PATCH 37/63] switch on V_FLAG_TRUSTED_FIRST by default for compatibility with OpenSSL 1.1.1 --- .../openssl/x509store/VerifyParameter.java | 66 ++++++++++--------- 1 file changed, 34 insertions(+), 32 deletions(-) diff --git a/src/main/java/org/jruby/ext/openssl/x509store/VerifyParameter.java b/src/main/java/org/jruby/ext/openssl/x509store/VerifyParameter.java index f176f5e7..2e28f1e0 100644 --- a/src/main/java/org/jruby/ext/openssl/x509store/VerifyParameter.java +++ b/src/main/java/org/jruby/ext/openssl/x509store/VerifyParameter.java @@ -35,6 +35,8 @@ import org.bouncycastle.asn1.ASN1Primitive; +import static org.jruby.ext.openssl.x509store.X509Utils.*; + /** * c: X509_VERIFY_PARAM * @@ -294,44 +296,44 @@ public static void tableCleanup() { private final static VerifyParameter[] defaultTable = new VerifyParameter[] { new VerifyParameter( - "default", /* X509 default parameters */ - 0, /* Check time */ - 0, /* internal flags */ - 0, /* flags */ - 0, /* purpose */ - 0, /* trust */ - 100, /* depth */ - null /* policies */ + "default", /* X509 default parameters */ + 0, /* Check time */ + 0, /* internal flags */ + V_FLAG_TRUSTED_FIRST, /* flags */ + 0, /* purpose */ + 0, /* trust */ + 100, /* depth */ + null /* policies */ ), new VerifyParameter( - "pkcs7", /* SSL/TLS client parameters */ - 0, /* Check time */ - 0, /* internal flags */ - 0, /* flags */ - X509Utils.X509_PURPOSE_SMIME_SIGN, /* purpose */ - X509Utils.X509_TRUST_EMAIL, /* trust */ - -1, /* depth */ - null /* policies */ + "pkcs7", /* S/MIME sign parameters */ + 0, /* Check time */ + 0, /* internal flags */ + 0, /* flags */ + X509_PURPOSE_SMIME_SIGN, /* purpose */ + X509_TRUST_EMAIL, /* trust */ + -1, /* depth */ + null /* policies */ ), new VerifyParameter( - "ssl_client", /* SSL/TLS client parameters */ - 0, /* Check time */ - 0, /* internal flags */ - 0, /* flags */ - X509Utils.X509_PURPOSE_SSL_CLIENT, /* purpose */ - X509Utils.X509_TRUST_SSL_CLIENT, /* trust */ - -1, /* depth */ - null /* policies */ + "ssl_client", /* SSL/TLS client parameters */ + 0, /* Check time */ + 0, /* internal flags */ + 0, /* flags */ + X509_PURPOSE_SSL_CLIENT, /* purpose */ + X509_TRUST_SSL_CLIENT, /* trust */ + -1, /* depth */ + null /* policies */ ), new VerifyParameter( - "ssl_server", /* SSL/TLS server parameters */ - 0, /* Check time */ - 0, /* internal flags */ - 0, /* flags */ - X509Utils.X509_PURPOSE_SSL_SERVER, /* purpose */ - X509Utils.X509_TRUST_SSL_SERVER, /* trust */ - -1, /* depth */ - null /* policies */ + "ssl_server", /* SSL/TLS server parameters */ + 0, /* Check time */ + 0, /* internal flags */ + 0, /* flags */ + X509_PURPOSE_SSL_SERVER, /* purpose */ + X509_TRUST_SSL_SERVER, /* trust */ + -1, /* depth */ + null /* policies */ )}; private final static List parameterTable = new ArrayList(); From 6b2c7772f43e435fb3eb39c651e2f4f0afe78bd8 Mon Sep 17 00:00:00 2001 From: kares Date: Tue, 19 Oct 2021 18:12:29 +0200 Subject: [PATCH 38/63] revisit and do more 1.1.1 verify compat --- .../ext/openssl/x509store/StoreContext.java | 47 +++++++++++++------ 1 file changed, 32 insertions(+), 15 deletions(-) diff --git a/src/main/java/org/jruby/ext/openssl/x509store/StoreContext.java b/src/main/java/org/jruby/ext/openssl/x509store/StoreContext.java index a59eb99a..67745414 100644 --- a/src/main/java/org/jruby/ext/openssl/x509store/StoreContext.java +++ b/src/main/java/org/jruby/ext/openssl/x509store/StoreContext.java @@ -135,14 +135,27 @@ public Object getApplicationData() { return getExtraData(0); } - /** - * c: X509_STORE_CTX_get1_issuer + /*- + * Try to get issuer certificate from store. Due to limitations + * of the API this can only retrieve a single certificate matching + * a given subject name. However it will fill the cache with all + * matching certificates, so we can examine the cache for all + * matches. + * + * Return values are: + * 1 lookup successful. + * 0 certificate not found. + * -1 some other error. + * + * int X509_STORE_CTX_get1_issuer(X509 **issuer, X509_STORE_CTX *ctx, X509 *x) */ int getFirstIssuer(final X509AuxCertificate[] _issuer, final X509AuxCertificate x) throws Exception { + int ok; + // _issuer[0] = null; final Name xn = new Name( x.getIssuerX500Principal() ); final X509Object[] s_obj = new X509Object[1]; - int ok = store == null ? 0 : getBySubject(X509Utils.X509_LU_X509, xn, s_obj); - if ( ok != X509Utils.X509_LU_X509 ) { + ok = store == null ? 0 : getBySubject(X509_LU_X509, xn, s_obj); + if (ok != 1) { if ( ok == X509Utils.X509_LU_RETRY ) { X509Error.addError(X509Utils.X509_R_SHOULD_RETRY); return -1; @@ -170,7 +183,8 @@ else if ( ok != X509Utils.X509_LU_FAIL ) { /* Look through all matching certificates for a suitable issuer */ for ( int i = idx; i < objects.size(); i++ ) { final X509Object pobj = objects.get(i); - if ( pobj.type() != X509Utils.X509_LU_X509 ) { + /* See if we've run past the matches */ + if (pobj.type() != X509_LU_X509) { break; // return 0 } final X509AuxCertificate x509 = ((Certificate) pobj).cert; @@ -695,6 +709,8 @@ public void setDefault(String name) { public int getBySubject(int type, Name name, X509Object[] ret) throws Exception { final Store store = this.store; + if (store == null) return 0; + X509Object tmp = X509Object.retrieveBySubject(store.getObjects(), type, name); if (tmp == null || type == X509_LU_CRL) { for (Lookup lu : store.getCertificateMethods()) { @@ -966,10 +982,10 @@ int verify_chain() throws Exception { * instantiate chain public key parameters. */ if ((ok = build_chain()) == 0 || - (ok = check_chain_extensions()) == 0 // || + (ok = check_chain_extensions()) == 0 || //(ok = check_auth_level(ctx)) == 0 || - //(ok = check_id()) == 0 || 1) - ); + //(ok = check_id()) == 0 || + true); if (ok == 0 || (ok = checkRevocation.call(this)) == 0) return ok; @@ -1012,6 +1028,9 @@ int build_chain() throws Exception { int depth; int ok; + /* Our chain starts with a single untrusted element. */ + assert num == 1 && num_untrusted == num; + /* * Set up search policy, untrusted if possible, trusted-first if enabled. * If we're doing DANE and not doing PKIX-TA/PKIX-EE, we never look in the @@ -1069,7 +1088,7 @@ int build_chain() throws Exception { * would be a-priori too long. */ if ((search & S_DOTRUSTED) != 0) { - int i = num = chain.size(); + num = chain.size(); int i = num; if ((search & S_DOALTERNATE) != 0) { /* * As high up the chain as we can, look for an alternative @@ -1143,7 +1162,6 @@ int build_chain() throws Exception { */ if (!x.equals(xtmp)) { /* Self-signed untrusted mimic. */ - xtmp = null; ok = 0; } else { num_untrusted = --num; @@ -1234,9 +1252,10 @@ int build_chain() throws Exception { chain.add(xtmp); x = xtmp; - num_untrusted++; + ++num_untrusted; ss = cert_self_signed(xtmp); + trust = X509_TRUST_UNTRUSTED; // switch (trust = check_dane_issuer(...)) } } // sk_X509_free(sktmp) @@ -1264,8 +1283,9 @@ int build_chain() throws Exception { if (num > depth) { return verify_cb_cert(null, num - 1, V_ERR_CERT_CHAIN_TOO_LONG); } - if (ss && num == 1) + if (ss && num == 1) { return verify_cb_cert(null, num - 1, V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT); + } if (ss) { return verify_cb_cert(null, num - 1, V_ERR_SELF_SIGNED_CERT_IN_CHAIN); } @@ -1281,9 +1301,7 @@ public X509AuxCertificate findIssuer(final List certs, final X509AuxCertificate cert, final boolean check_time) throws Exception { for ( X509AuxCertificate issuer : certs ) { if ( checkIssued.call(this, cert, issuer) != 0 ) { - if (!check_time || x509_check_cert_time(issuer, -1)) return issuer; - //return issuer; } } return null; @@ -1479,7 +1497,6 @@ private int check_purpose(X509AuxCertificate x, int purpose, int depth, byte mus case X509_TRUST_REJECTED: break; default: - // TODO X509_check_purpose(x, purpose, must_be_ca) passing down must_be_ca == -1 switch (Purpose.checkPurpose(x, verifyParameter.purpose, must_be_ca > 0 ? 1 : 0)) { // X509_check_purpose(x, purpose, must_be_ca) case 1: return 1; From 58d1f60457330b3ab4cc41c9495ba70a3d08f119 Mon Sep 17 00:00:00 2001 From: kares Date: Tue, 19 Oct 2021 19:12:04 +0200 Subject: [PATCH 39/63] [refactor] minor - align param getter naming --- src/main/java/org/jruby/ext/openssl/SSLContext.java | 2 +- .../java/org/jruby/ext/openssl/x509store/Store.java | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/main/java/org/jruby/ext/openssl/SSLContext.java b/src/main/java/org/jruby/ext/openssl/SSLContext.java index 7d1ac22c..618f7b16 100644 --- a/src/main/java/org/jruby/ext/openssl/SSLContext.java +++ b/src/main/java/org/jruby/ext/openssl/SSLContext.java @@ -945,7 +945,7 @@ StoreContext createStoreContext(final String purpose) { // for verify_cb storeContext.setExtraData(1, store.getExtraData(1)); if ( purpose != null ) storeContext.setDefault(purpose); - storeContext.verifyParameter.inherit(store.verifyParameter); + storeContext.getParam().inherit(store.getParam()); return storeContext; } diff --git a/src/main/java/org/jruby/ext/openssl/x509store/Store.java b/src/main/java/org/jruby/ext/openssl/x509store/Store.java index 606a6acb..bf5a4020 100644 --- a/src/main/java/org/jruby/ext/openssl/x509store/Store.java +++ b/src/main/java/org/jruby/ext/openssl/x509store/Store.java @@ -81,7 +81,7 @@ interface LookupCerts { private volatile X509Object[] objects = NULL_OBJECTS; private volatile Lookup[] certLookups = NULL_LOOKUP; - public final VerifyParameter verifyParameter; + final VerifyParameter verifyParameter; VerifyFunction verify; VerifyCallbackFunction verifyCallback; @@ -118,10 +118,6 @@ public List getCertificateMethods() { return Arrays.asList(certLookups); } - public VerifyParameter getVerifyParameter() { - return verifyParameter; - } - /** * c: X509_STORE_set_verify_func */ @@ -197,6 +193,10 @@ public int setTrust(int trust) { return verifyParameter.setTrust(trust); } + public VerifyParameter getParam() { + return verifyParameter; + } + /** * c: X509_STORE_set1_param */ From b1b8b0c571a4b18db6eff2f561b7ea91088075a4 Mon Sep 17 00:00:00 2001 From: kares Date: Tue, 19 Oct 2021 19:33:43 +0200 Subject: [PATCH 40/63] [test] a few variants on alt chain + trusted first --- src/test/ruby/ssl/test_ssl.rb | 186 ++++++++++++++++++++++++++++++++++ 1 file changed, 186 insertions(+) diff --git a/src/test/ruby/ssl/test_ssl.rb b/src/test/ruby/ssl/test_ssl.rb index 9d9e51d0..43232524 100644 --- a/src/test/ruby/ssl/test_ssl.rb +++ b/src/test/ruby/ssl/test_ssl.rb @@ -317,4 +317,190 @@ def test_set_custom_params end end + LEAF_CERTIFICATE = OpenSSL::X509::Certificate.new <<-EOF +-----BEGIN CERTIFICATE----- +MIIFKDCCBBCgAwIBAgISBP+uKglvwxGq302F+yCqxvnXMA0GCSqGSIb3DQEBCwUA +MDIxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1MZXQncyBFbmNyeXB0MQswCQYDVQQD +EwJSMzAeFw0yMTA4MTEwOTAxMzdaFw0yMTExMDkwOTAxMzVaMBwxGjAYBgNVBAMT +EWdlb2lwLmVsYXN0aWMuZGV2MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC +AQEAtazxd/2FWW1O5evHkDnPi4vcZJDFxs8V0tlI2ppf/OTymlBHMbzBE3BsUEP7 +SkT+6kPnqQoy85S66zT4f2XyQfSWUZJeMPMcODl5P0SXEBlKv+ElRYvrsUpuc0ZH +ZTIM3+ueUY5M3Xmo9ao+I5evahr4Pf1laRWhHRLzFdKiMn7r1/qXf+PzKqZlzLng +cULtVpCTZlOk7CwrsAxwTYdFe1Z0b2ebKs793Ghag2V3D2YtCMuqLa1GP1sBsFRT +v1XPehXb5UOWffp3RJnUoG3n7K5cPI6G+fUAGRF3wxKuH+PYyW6/irb5+v4CVVSi +z+f29zDYeOc+baWGWFfymktslwIDAQABo4ICTDCCAkgwDgYDVR0PAQH/BAQDAgWg +MB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjAMBgNVHRMBAf8EAjAAMB0G +A1UdDgQWBBQ23ntd4n192uVjxt9C0B18QYWMyzAfBgNVHSMEGDAWgBQULrMXt1hW +y65QCUDmH6+dixTCxjBVBggrBgEFBQcBAQRJMEcwIQYIKwYBBQUHMAGGFWh0dHA6 +Ly9yMy5vLmxlbmNyLm9yZzAiBggrBgEFBQcwAoYWaHR0cDovL3IzLmkubGVuY3Iu +b3JnLzAcBgNVHREEFTATghFnZW9pcC5lbGFzdGljLmRldjBMBgNVHSAERTBDMAgG +BmeBDAECATA3BgsrBgEEAYLfEwEBATAoMCYGCCsGAQUFBwIBFhpodHRwOi8vY3Bz +LmxldHNlbmNyeXB0Lm9yZzCCAQQGCisGAQQB1nkCBAIEgfUEgfIA8AB1AH0+8viP +/4hVaCTCwMqeUol5K8UOeAl/LmqXaJl+IvDXAAABezSpB0oAAAQDAEYwRAIgC5B1 +huzXAJCbtfWO5GGMVj930XNoNPGQj6o8yJfMQnMCIBdlncSV2rymFbZG7Q2PSAim +7/PkW/2qD3Vt8Ald8u3DAHcARJRlLrDuzq/EQAfYqP4owNrmgr7YyzG1P9MzlrW2 +gagAAAF7NKkJHAAABAMASDBGAiEAnWU3nUNjdHdrE62v0y45WDLj6eyfXkIxAh9Z +GAA2wJACIQDtKZNFze3mAj7pE6m3AZMfnq4N0VvO2Ahr0HbpN/xWzDANBgkqhkiG +9w0BAQsFAAOCAQEABWFFyolbYnyqDA8ckU0Lm7btCM78CeljjKxVCGTqhlntJhhH +NBJcRArzCBkres7Z4yySiJ1vSUXNVvGITVCi2d/zJ5SxBDoT5v8IjEb98KH//9u3 +Jb1CfuEADhnEUXjyf4GeIiTHtdKX36jGwTRO3YIa52G6HONbOnQBgcwn8FpYJdIj +3C58o5AxWRcVVQbaCFxjGcCLSUSQsJxzilsYE+xVqc+d5GftG3Nmy6l3Ht84693n +UwMrb/rlsQC163gtdVEN/GFCeLU+UfFGuSeCmUM3SmAIVfD/yjLvisVpf70pV0Jg +p1Px196NI71smu8LxrhX78ErTrR4GpDkx4W+uw== +-----END CERTIFICATE----- + EOF + + + EXPIRED_DST_ROOT_CA_X3 = OpenSSL::X509::Certificate.new <<-EOF +-----BEGIN CERTIFICATE----- +MIIDSjCCAjKgAwIBAgIQRK+wgNajJ7qJMDmGLvhAazANBgkqhkiG9w0BAQUFADA/ +MSQwIgYDVQQKExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4xFzAVBgNVBAMT +DkRTVCBSb290IENBIFgzMB4XDTAwMDkzMDIxMTIxOVoXDTIxMDkzMDE0MDExNVow +PzEkMCIGA1UEChMbRGlnaXRhbCBTaWduYXR1cmUgVHJ1c3QgQ28uMRcwFQYDVQQD +Ew5EU1QgUm9vdCBDQSBYMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB +AN+v6ZdQCINXtMxiZfaQguzH0yxrMMpb7NnDfcdAwRgUi+DoM3ZJKuM/IUmTrE4O +rz5Iy2Xu/NMhD2XSKtkyj4zl93ewEnu1lcCJo6m67XMuegwGMoOifooUMM0RoOEq +OLl5CjH9UL2AZd+3UWODyOKIYepLYYHsUmu5ouJLGiifSKOeDNoJjj4XLh7dIN9b +xiqKqy69cK3FCxolkHRyxXtqqzTWMIn/5WgTe1QLyNau7Fqckh49ZLOMxt+/yUFw +7BZy1SbsOFU5Q9D8/RhcQPGX69Wam40dutolucbY38EVAjqr2m7xPi71XAicPNaD +aeQQmxkqtilX4+U9m5/wAl0CAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNV +HQ8BAf8EBAMCAQYwHQYDVR0OBBYEFMSnsaR7LHH62+FLkHX/xBVghYkQMA0GCSqG +SIb3DQEBBQUAA4IBAQCjGiybFwBcqR7uKGY3Or+Dxz9LwwmglSBd49lZRNI+DT69 +ikugdB/OEIKcdBodfpga3csTS7MgROSR6cz8faXbauX+5v3gTt23ADq1cEmv8uXr +AvHRAosZy5Q6XkjEGB5YGV8eAlrwDPGxrancWYaLbumR9YbK+rlmM6pZW87ipxZz +R8srzJmwN0jP41ZL9c8PDHIyh8bwRLtTcm1D9SZImlJnt1ir/md2cXjbDaJWFBM5 +JDGFoqgCWjBH4d1QB7wCCZAA62RjYJsWvIjJEubSfZGL+T0yjWW06XyxV3bqxbYo +Ob8VZRzI9neWagqNdwvYkQsEjgfbKbYK7p2CNTUQ +-----END CERTIFICATE----- + EOF + + def test_cert_verify_expired1_lets_encrypt_cross_signed_root + # reproducer for https://github.com/jruby/jruby-openssl/issues/236 + # + # In this reproducer we have a leaf certificate with two possible chains: + # a) leaf -> intermediate cert A -> ISRG Root X1 cross-signed by (expired) DST ROOT CA X3 -> (expired) DST ROOT CA X3 + # b) leaf -> intermediate cert B -> ISRG Root X1 + # JRuby will produce chain a) causing an error, while CRuby produces a valid chain b) + + root_bundle = [ + # Expired DST ROOT CA X3 + EXPIRED_DST_ROOT_CA_X3, + # active ISRG Root X1 + OpenSSL::X509::Certificate.new(File.read(File.expand_path('../letsencrypt/isrgrootx1.pem', __FILE__))), + # ISRG Root X1 cross-signed by (expired) DST ROOT CA X3 + OpenSSL::X509::Certificate.new(File.read(File.expand_path('../letsencrypt/isrg-root-x1-cross-signed.pem', __FILE__))) + ] + + cert_store = OpenSSL::X509::Store.new + root_bundle.each { |cert| cert_store.add_cert cert } + + # the endpoint will send the leaf node + these two intermediate certs + chain = [ + # Intermediate cert from expired CA + OpenSSL::X509::Certificate.new(File.read(File.expand_path('../letsencrypt/lets-encrypt-r3-cross-signed.pem', __FILE__))), + # Valid Intermediate cert + OpenSSL::X509::Certificate.new(File.read(File.expand_path('../letsencrypt/lets-encrypt-r3.pem', __FILE__))), + ] + + # let's try to validate the leaf+chain against the root bundle + ok = cert_store.verify(LEAF_CERTIFICATE, chain) + + # pp cert_store.chain if $VERBOSE + + assert_equal true, ok + assert_equal 'ok', cert_store.error_string + assert_equal ["/CN=geoip.elastic.dev", + "/C=US/O=Let's Encrypt/CN=R3", + "/C=US/O=Internet Security Research Group/CN=ISRG Root X1"], + cert_store.chain.map { |cert| cert.subject.to_s } + + # 0.10.7 + # [#, + # issuer=#, + # serial=#, + # not_before=2021-08-11 09:01:37 UTC, + # not_after=2021-11-09 09:01:35 UTC>, + # #, + # issuer=#, + # serial=#, + # not_before=2020-10-07 19:21:40 UTC, + # not_after=2021-09-29 19:21:40 UTC>, + # #, + # issuer=#, + # serial=#, + # not_before=2000-09-30 21:12:19 UTC, + # not_after=2021-09-30 14:01:15 UTC>] + # 10 + # certificate has expired + end + + def test_cert_verify_expired2_lets_encrypt_cross_signed_intermediate + + root_bundle = [ + # Expired DST ROOT CA X3 + EXPIRED_DST_ROOT_CA_X3, + # active ISRG Root X1 + OpenSSL::X509::Certificate.new(File.read(File.expand_path('../letsencrypt/isrgrootx1.pem', __FILE__))), + # ISRG Root X1 cross-signed by DST ROOT CA X3 (which is expired) + #OpenSSL::X509::Certificate.new(File.read(File.expand_path('../letsencrypt/isrg-root-x1-cross-signed.pem', __FILE__))) + ] + + cert_store = OpenSSL::X509::Store.new + root_bundle.each { |cert| cert_store.add_cert cert } + + # cross-signed cert is sent from the server : + chain = [ + #LEAF_CERTIFICATE, + # Valid Intermediate cert + OpenSSL::X509::Certificate.new(File.read(File.expand_path('../letsencrypt/lets-encrypt-r3.pem', __FILE__))), + # ISRG Root X1 cross-signed by DST ROOT CA X3 + OpenSSL::X509::Certificate.new(File.read(File.expand_path('../letsencrypt/isrg-root-x1-cross-signed.pem', __FILE__))) + ] + + ok = cert_store.verify(LEAF_CERTIFICATE, chain) + + # pp cert_store.chain if $VERBOSE + + assert_equal ["/CN=geoip.elastic.dev", + "/C=US/O=Let's Encrypt/CN=R3", + "/C=US/O=Internet Security Research Group/CN=ISRG Root X1"], + cert_store.chain.map { |cert| cert.subject.to_s } + + assert_equal true, ok # fails in JOSSL 0.10.7 error: 10 (certificate has expired) + assert_equal 'ok', cert_store.error_string + end + + def test_cert_verify_expired0_lets_encrypt # base_line + root_bundle = [ + # Expired DST ROOT CA X3 + #EXPIRED_DST_ROOT_CA_X3, # should be fine since we do not have the expired around + # active ISRG Root X1 + OpenSSL::X509::Certificate.new(File.read(File.expand_path('../letsencrypt/isrgrootx1.pem', __FILE__))), + # ISRG Root X1 cross-signed by (expired) DST ROOT CA X3 + OpenSSL::X509::Certificate.new(File.read(File.expand_path('../letsencrypt/isrg-root-x1-cross-signed.pem', __FILE__))) + ] + + cert_store = OpenSSL::X509::Store.new + root_bundle.each { |cert| cert_store.add_cert cert } + + chain = [ + # Intermediate cert from expired CA + OpenSSL::X509::Certificate.new(File.read(File.expand_path('../letsencrypt/lets-encrypt-r3-cross-signed.pem', __FILE__))), + # Valid Intermediate cert + OpenSSL::X509::Certificate.new(File.read(File.expand_path('../letsencrypt/lets-encrypt-r3.pem', __FILE__))), + ] + + ok = cert_store.verify(LEAF_CERTIFICATE, chain) + + assert ok # works in JOSSL 0.10.7 + assert_equal 'ok', cert_store.error_string + assert_equal ["/CN=geoip.elastic.dev", + "/C=US/O=Let's Encrypt/CN=R3", + "/C=US/O=Internet Security Research Group/CN=ISRG Root X1"], + cert_store.chain.map { |cert| cert.subject.to_s } + end + end From e22836298c8d69161fa015970b9e22fa7af08777 Mon Sep 17 00:00:00 2001 From: kares Date: Wed, 20 Oct 2021 16:29:59 +0200 Subject: [PATCH 41/63] ported bits for check_crl (wip) unused for now due test fails but we're still plan using the new time checks --- .../ext/openssl/x509store/StoreContext.java | 160 +++++++++++++++++- 1 file changed, 151 insertions(+), 9 deletions(-) diff --git a/src/main/java/org/jruby/ext/openssl/x509store/StoreContext.java b/src/main/java/org/jruby/ext/openssl/x509store/StoreContext.java index 67745414..e77f0ebc 100644 --- a/src/main/java/org/jruby/ext/openssl/x509store/StoreContext.java +++ b/src/main/java/org/jruby/ext/openssl/x509store/StoreContext.java @@ -322,7 +322,7 @@ public int init(X509AuxCertificate cert, List untrusted_chai this.verify = null; this.checkRevocation = StoreContext.check_revocation; this.getCRL = defaultGetCRL; - this.checkCRL = defaultCheckCRL; + this.checkCRL = check_crl_legacy; this.certificateCRL = defaultCertificateCRL; if ( store != null ) { @@ -1812,10 +1812,56 @@ public int checkCertificate() throws Exception { return ok; } - /** - * c: check_crl_time - */ - public int checkCRLTime(X509CRL crl, int notify) throws Exception { + /* Check CRL times against values in X509_STORE_CTX */ + private boolean check_crl_time(X509CRL crl, final boolean notify) throws Exception { + final Date pTime; + + if (notify) this.currentCRL = crl; + + if ((getParam().flags & V_FLAG_USE_CHECK_TIME) != 0) { + pTime = getParam().checkTime; + } else if ((getParam().flags & V_FLAG_NO_CHECK_TIME) != 0) { + return true; + } else { + pTime = Calendar.getInstance().getTime(); + } + + int i = crl.getThisUpdate().compareTo(pTime); + if (i == 0) { + if (!notify) return false; + if (verify_cb_crl(V_ERR_ERROR_IN_CRL_LAST_UPDATE_FIELD) == 0) + return false; + } + + if (i > 0) { + if (!notify) return false; + if (verify_cb_crl(V_ERR_CRL_NOT_YET_VALID) == 0) + return false; + } + + if (crl.getNextUpdate() != null) { + i = crl.getNextUpdate().compareTo(pTime); + + if (i == 0) { + if (!notify) return false; + if (verify_cb_crl(V_ERR_ERROR_IN_CRL_NEXT_UPDATE_FIELD) == 0) + return false; + } + /* Ignore expiry of base CRL is delta is valid */ + if ((i < 0) /*&& !(ctx->current_crl_score & CRL_SCORE_TIME_DELTA)*/) { + if (!notify) return false; + if (verify_cb_crl(V_ERR_CRL_HAS_EXPIRED) == 0) + return false; + } + } + + if (notify) this.currentCRL = null; + + return true; + } + + @Deprecated // legacy check_crl_time + private int checkCRLTime(X509CRL crl, int notify) throws Exception { currentCRL = crl; final Date pTime; if ((getParam().flags & V_FLAG_USE_CHECK_TIME) != 0) { @@ -1893,6 +1939,18 @@ private int verify_cb_cert(X509AuxCertificate x, int depth, int err) throws Exce return verifyCallback.call(this, 0); // ctx->verify_cb(0, ctx) } + /*- + * Inform the verify callback of an error, CRL-specific variant. Here, the + * error depth and certificate are already set, we just specify the error + * number. + * + * Returns 0 to abort verification with an error, non-zero to continue. + */ + private int verify_cb_crl(int err) throws Exception { + this.error = err; + return verifyCallback.call(this, 0); // ctx->verify_cb(0, ctx) + } + final static Store.GetIssuerFunction getFirstIssuer = new Store.GetIssuerFunction() { public int call(StoreContext context, X509AuxCertificate[] issuer, X509AuxCertificate cert) throws Exception { return context.getFirstIssuer(issuer, cert); @@ -2180,10 +2238,94 @@ public int call(final StoreContext context, final X509CRL[] crls, X509AuxCertifi } }; - /** - * c: check_crl - */ - final static Store.CheckCRLFunction defaultCheckCRL = new Store.CheckCRLFunction() { + // TODO unused due incomplete - needs score support to pass test_x509store.rb tests? + /* Check CRL validity */ + private int check_crl(X509CRL crl) throws Exception { + final X509AuxCertificate issuer; + int cnum = this.errorDepth; + int chnum = this.chain.size() - 1; + + /* if we have an alternative CRL issuer cert use that */ + if (this.currentIssuer != null) + issuer = this.currentIssuer; + /* + * Else find CRL issuer: if not last certificate then issuer is next + * certificate in chain. + */ + else if (cnum < chnum) + issuer = this.chain.get(cnum + 1); + else { + issuer = this.chain.get(chnum); + /* If not self signed, can't check signature */ + if (this.checkIssued.call(this, issuer, issuer) == 0 && + verify_cb_crl(V_ERR_UNABLE_TO_GET_CRL_ISSUER) == 0) + return 0; + } + + if (issuer == null) { + return 1; + } + + /* + * Skip most tests for deltas because they have already been done + */ + //if (!crl->base_crl_number) { + /* Check for cRLSign bit if keyUsage present */ + if (issuer.getKeyUsage() != null && !issuer.getKeyUsage()[6]) { + if (verify_cb_crl(V_ERR_KEYUSAGE_NO_CRL_SIGN) == 0) return 0; + } + + //if (!(ctx->current_crl_score & CRL_SCORE_SCOPE) && + // !verify_cb_crl(ctx, X509_V_ERR_DIFFERENT_CRL_SCOPE)) + // return 0; + // + //if (!(ctx->current_crl_score & CRL_SCORE_SAME_PATH) && + // check_crl_path(ctx, ctx->current_issuer) <= 0 && + // !verify_cb_crl(ctx, X509_V_ERR_CRL_PATH_VALIDATION_ERROR)) + // return 0; + // + //if ((crl->idp_flags & IDP_INVALID) && + // !verify_cb_crl(ctx, X509_V_ERR_INVALID_EXTENSION)) + // return 0; + //} + + //if (!(ctx->current_crl_score & CRL_SCORE_TIME) && + // !check_crl_time(ctx, crl, 1)) + // return 0; + if (!check_crl_time(crl, true)) return 0; + + /* Attempt to get issuer certificate public key */ + final PublicKey ikey = issuer.getPublicKey(); // X509_get0_pubkey(issuer) + + if (ikey == null && verify_cb_crl(V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY) == 0) { + return 0; + } + + if (ikey != null) { + //int rv = X509_CRL_check_suiteb(crl, ikey, ctx->param->flags); + // + //if (rv != V_OK && verify_cb_crl(rv) == 0) { + // return 0; + //} + /* Verify CRL signature */ + try { + SecurityHelper.verify(crl, ikey); // X509_CRL_verify + } + catch (GeneralSecurityException ex) { + if (verify_cb_crl(V_ERR_CRL_SIGNATURE_FAILURE) == 0) return 0; + } + } + return 1; + } + + /* Check CRL validity */ + final static Store.CheckCRLFunction check_crl = new Store.CheckCRLFunction() { + public int call(final StoreContext ctx, final X509CRL crl) throws Exception { + return ctx.check_crl(crl); + } + }; + + final static Store.CheckCRLFunction check_crl_legacy = new Store.CheckCRLFunction() { public int call(final StoreContext context, final X509CRL crl) throws Exception { final int errorDepth = context.errorDepth; final int lastInChain = context.chain.size() - 1; From a1251757b49515ae87a3fb7c7d354649c31a35a7 Mon Sep 17 00:00:00 2001 From: kares Date: Wed, 20 Oct 2021 16:32:08 +0200 Subject: [PATCH 42/63] [refactor] impl and use EXFLAG_PROXY in ported code --- .../java/org/jruby/ext/openssl/x509store/StoreContext.java | 2 +- .../org/jruby/ext/openssl/x509store/X509AuxCertificate.java | 4 ++++ src/main/java/org/jruby/ext/openssl/x509store/X509Utils.java | 2 +- 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/jruby/ext/openssl/x509store/StoreContext.java b/src/main/java/org/jruby/ext/openssl/x509store/StoreContext.java index e77f0ebc..e192f08a 100644 --- a/src/main/java/org/jruby/ext/openssl/x509store/StoreContext.java +++ b/src/main/java/org/jruby/ext/openssl/x509store/StoreContext.java @@ -1551,7 +1551,7 @@ private int check_chain_extensions() throws Exception { if (verify_cb_cert(x, i, V_ERR_UNHANDLED_CRITICAL_EXTENSION) == 0) return 0; } - if (allow_proxy_certs == false && x.getExtensionValue("1.3.6.1.5.5.7.1.14") != null) { // && (x->ex_flags & EXFLAG_PROXY) + if (allow_proxy_certs == false && (x.getExFlags() & EXFLAG_PROXY) != 0) { if (verify_cb_cert(x, i, V_ERR_PROXY_CERTIFICATES_NOT_ALLOWED) == 0) return 0; } diff --git a/src/main/java/org/jruby/ext/openssl/x509store/X509AuxCertificate.java b/src/main/java/org/jruby/ext/openssl/x509store/X509AuxCertificate.java index 2587cc4f..81788578 100644 --- a/src/main/java/org/jruby/ext/openssl/x509store/X509AuxCertificate.java +++ b/src/main/java/org/jruby/ext/openssl/x509store/X509AuxCertificate.java @@ -181,6 +181,10 @@ private int computeExFlags() throws IOException { flags |= X509Utils.EXFLAG_XKUSAGE; } + if (getExtensionValue("1.3.6.1.5.5.7.1.14") != null) { + flags |= X509Utils.EXFLAG_PROXY; + } + return flags; } diff --git a/src/main/java/org/jruby/ext/openssl/x509store/X509Utils.java b/src/main/java/org/jruby/ext/openssl/x509store/X509Utils.java index ce2352a4..9bb2541d 100644 --- a/src/main/java/org/jruby/ext/openssl/x509store/X509Utils.java +++ b/src/main/java/org/jruby/ext/openssl/x509store/X509Utils.java @@ -636,7 +636,7 @@ else if (maybeCertFile != null && new File(maybeCertFile).exists()) { /* EXFLAG_SET is set to indicate that some values have been precomputed */ //public static final int EXFLAG_SET=0x100; //public static final int EXFLAG_CRITICAL=0x200; - //public static final int EXFLAG_PROXY=0x400; + public static final int EXFLAG_PROXY=0x400; //public static final int EXFLAG_INVALID_POLICY=0x800; //public static final int EXFLAG_FRESHEST=0x1000; From cb65b34b69b90353d5076ea4b00dac7bb3b6e89b Mon Sep 17 00:00:00 2001 From: kares Date: Wed, 20 Oct 2021 16:33:12 +0200 Subject: [PATCH 43/63] [refactor] debug assertion failures --- .../java/org/jruby/ext/openssl/x509store/StoreContext.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/main/java/org/jruby/ext/openssl/x509store/StoreContext.java b/src/main/java/org/jruby/ext/openssl/x509store/StoreContext.java index e192f08a..3e082227 100644 --- a/src/main/java/org/jruby/ext/openssl/x509store/StoreContext.java +++ b/src/main/java/org/jruby/ext/openssl/x509store/StoreContext.java @@ -47,6 +47,7 @@ import org.bouncycastle.asn1.ASN1InputStream; import org.bouncycastle.asn1.ASN1Integer; import org.bouncycastle.asn1.ASN1Sequence; +import org.jruby.ext.openssl.OpenSSL; import org.jruby.ext.openssl.SecurityHelper; import static org.jruby.ext.openssl.x509store.X509Error.addError; @@ -1135,6 +1136,7 @@ int build_chain() throws Exception { */ if ((search & S_DOALTERNATE) != 0) { if (!(num > i && i > 0 && ss == false)) { // ossl_assert + OpenSSL.debug(this + " assert failure (num > i && i > 0 && ss == false)"); addError(ERR_R_INTERNAL_ERROR); trust = X509_TRUST_REJECTED; this.error = V_ERR_UNSPECIFIED; @@ -1184,6 +1186,7 @@ int build_chain() throws Exception { */ if (ok != 0) { if (!(num_untrusted <= num)) { // ossl_assert + OpenSSL.debug(this + " assert failure (num_untrusted <= num)"); addError(ERR_R_INTERNAL_ERROR); trust = X509_TRUST_REJECTED; this.error = V_ERR_UNSPECIFIED; @@ -1227,6 +1230,7 @@ int build_chain() throws Exception { if ((search & S_DOUNTRUSTED) != 0) { num = chain.size(); if (!(num == num_untrusted)) { // ossl_assert + OpenSSL.debug(this + " assert failure (num == num_untrusted)"); addError(ERR_R_INTERNAL_ERROR); trust = X509_TRUST_REJECTED; this.error = V_ERR_UNSPECIFIED; From dd58f668cf4ba7fc4de3456d69f644beefa583c8 Mon Sep 17 00:00:00 2001 From: kares Date: Wed, 20 Oct 2021 16:35:10 +0200 Subject: [PATCH 44/63] reviewed X509_check_issued ~ matches 1.1.1 version --- .../java/org/jruby/ext/openssl/x509store/X509Utils.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/org/jruby/ext/openssl/x509store/X509Utils.java b/src/main/java/org/jruby/ext/openssl/x509store/X509Utils.java index 9bb2541d..46616d72 100644 --- a/src/main/java/org/jruby/ext/openssl/x509store/X509Utils.java +++ b/src/main/java/org/jruby/ext/openssl/x509store/X509Utils.java @@ -206,10 +206,10 @@ static ASN1Primitive get(final byte[] input) throws IOException { return new ASN1InputStream(input).readObject(); } - /** - * c: X509_check_issued + /* + * c: X509_check_issued + x509_likely_issued + x509_signing_allowed */ - public static int checkIfIssuedBy(final X509AuxCertificate issuer, + static int checkIfIssuedBy(final X509AuxCertificate issuer, final X509AuxCertificate subject) throws IOException { if ( ! issuer.getSubjectX500Principal().equals(subject.getIssuerX500Principal()) ) { From 6e677132ef88e45fa9e46f03ca493545b0c79a1f Mon Sep 17 00:00:00 2001 From: kares Date: Wed, 20 Oct 2021 16:36:12 +0200 Subject: [PATCH 45/63] port get_issuer - we might need it later --- .../jruby/ext/openssl/x509store/StoreContext.java | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/main/java/org/jruby/ext/openssl/x509store/StoreContext.java b/src/main/java/org/jruby/ext/openssl/x509store/StoreContext.java index 3e082227..37dfbf10 100644 --- a/src/main/java/org/jruby/ext/openssl/x509store/StoreContext.java +++ b/src/main/java/org/jruby/ext/openssl/x509store/StoreContext.java @@ -754,6 +754,20 @@ List get1_certs(final Name nm) throws Exception { return sk; } + /* Get issuer, without duplicate suppression */ + private int get_issuer(X509AuxCertificate[] issuer, X509AuxCertificate cert) throws Exception { + final ArrayList saved_chain = this.chain; + int ok; + + this.chain = null; + try { + ok = this.getIssuer.call(this, issuer, cert); + } finally { + this.chain = saved_chain; + } + return ok; + } + private List matchCachedCertObjectsFromStore(final Name name) { ArrayList sk = new ArrayList(); for (X509Object obj : store.getObjects()) { From 2435a43ab3bd31d8fd1087f16287a4e63b6c72b1 Mon Sep 17 00:00:00 2001 From: kares Date: Wed, 20 Oct 2021 16:37:19 +0200 Subject: [PATCH 46/63] [refactor] minor - style used to resemble OpenSSL --- src/main/java/org/jruby/ext/openssl/x509store/StoreContext.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/jruby/ext/openssl/x509store/StoreContext.java b/src/main/java/org/jruby/ext/openssl/x509store/StoreContext.java index 37dfbf10..200c9a83 100644 --- a/src/main/java/org/jruby/ext/openssl/x509store/StoreContext.java +++ b/src/main/java/org/jruby/ext/openssl/x509store/StoreContext.java @@ -1515,7 +1515,7 @@ private int check_purpose(X509AuxCertificate x, int purpose, int depth, byte mus case X509_TRUST_REJECTED: break; default: - switch (Purpose.checkPurpose(x, verifyParameter.purpose, must_be_ca > 0 ? 1 : 0)) { // X509_check_purpose(x, purpose, must_be_ca) + switch (Purpose.checkPurpose(x, getParam().purpose, must_be_ca > 0 ? 1 : 0)) { // X509_check_purpose(x, purpose, must_be_ca) case 1: return 1; case 0: From 0613e6e19630f626fadf70356ce5d388fe8c9fc3 Mon Sep 17 00:00:00 2001 From: kares Date: Wed, 20 Oct 2021 16:38:36 +0200 Subject: [PATCH 47/63] use ported check_crl_time (in legacy as well) this should be fine since it just does more checks --- .../java/org/jruby/ext/openssl/x509store/StoreContext.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/jruby/ext/openssl/x509store/StoreContext.java b/src/main/java/org/jruby/ext/openssl/x509store/StoreContext.java index 200c9a83..90edd41f 100644 --- a/src/main/java/org/jruby/ext/openssl/x509store/StoreContext.java +++ b/src/main/java/org/jruby/ext/openssl/x509store/StoreContext.java @@ -2386,8 +2386,9 @@ public int call(final StoreContext context, final X509CRL crl) throws Exception } } - ok = context.checkCRLTime(crl, 1); - if ( ok == 0 ) return ok; + //ok = context.checkCRLTime(crl, 1); + //if ( ok == 0 ) return ok; + if (!context.check_crl_time(crl, true)) return 0; return 1; } From 220c82f37856323fb2158f6bce9116d1c1986550 Mon Sep 17 00:00:00 2001 From: kares Date: Wed, 20 Oct 2021 16:44:50 +0200 Subject: [PATCH 48/63] [todo] EXFLAG_SS isn't working for JOSSL atm --- .../java/org/jruby/ext/openssl/x509store/StoreContext.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/jruby/ext/openssl/x509store/StoreContext.java b/src/main/java/org/jruby/ext/openssl/x509store/StoreContext.java index 90edd41f..22c0ac7c 100644 --- a/src/main/java/org/jruby/ext/openssl/x509store/StoreContext.java +++ b/src/main/java/org/jruby/ext/openssl/x509store/StoreContext.java @@ -1660,8 +1660,8 @@ private int check_chain_extensions() throws Exception { /* Return 1 is a certificate is self signed */ private boolean cert_self_signed(X509AuxCertificate x) throws CertificateException, IOException { - Purpose.checkPurpose(x, -1, 0); - if ((x.getExFlags() & EXFLAG_SS) != 0) { + // Purpose.checkPurpose(x, -1, 0); + if ((x.getExFlags() & EXFLAG_SI) != 0) { // TODO EXFLAG_SS return true; } return false; From eddaa3500e589bd6981f9f77f1dbd2f4230631ed Mon Sep 17 00:00:00 2001 From: kares Date: Wed, 20 Oct 2021 16:46:08 +0200 Subject: [PATCH 49/63] [refactor] align legacy check_crl with 1.1.1 --- .../java/org/jruby/ext/openssl/x509store/StoreContext.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/main/java/org/jruby/ext/openssl/x509store/StoreContext.java b/src/main/java/org/jruby/ext/openssl/x509store/StoreContext.java index 22c0ac7c..57196f03 100644 --- a/src/main/java/org/jruby/ext/openssl/x509store/StoreContext.java +++ b/src/main/java/org/jruby/ext/openssl/x509store/StoreContext.java @@ -1812,6 +1812,10 @@ public int checkCertificate() throws Exception { cnum = errorDepth; x = chain.get(cnum); currentCertificate = x; + currentIssuer = null; + + if (x.getExtensionValue("1.3.6.1.5.5.7.1.14") != null) return 1; // (x.getExFlags() & EXFLAG_PROXY) != 0 + ok = getCRL.call(this, crl, x); if ( ok == 0 ) { error = X509Utils.V_ERR_UNABLE_TO_GET_CRL; From c14ed434f156e2bda8bb05f8daaa9278ecef1618 Mon Sep 17 00:00:00 2001 From: kares Date: Wed, 20 Oct 2021 16:48:11 +0200 Subject: [PATCH 50/63] [fix] do not assume object == in check_issued --- .../java/org/jruby/ext/openssl/x509store/StoreContext.java | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/main/java/org/jruby/ext/openssl/x509store/StoreContext.java b/src/main/java/org/jruby/ext/openssl/x509store/StoreContext.java index 57196f03..8fcbbb14 100644 --- a/src/main/java/org/jruby/ext/openssl/x509store/StoreContext.java +++ b/src/main/java/org/jruby/ext/openssl/x509store/StoreContext.java @@ -1998,13 +1998,10 @@ public int call(StoreContext context, X509AuxCertificate[] issuer, X509AuxCertif * * x509_vfy.c: static int check_issued(X509_STORE_CTX *ctx, X509 *x, X509 *issuer) */ - - // TODO logic mismtach - check store.checkIssued logic or always use legacy - final static Store.CheckIssuedFunction check_issued = new Store.CheckIssuedFunction() { public int call(StoreContext ctx, X509AuxCertificate x, X509AuxCertificate issuer) throws Exception { int ret; - if (x == issuer) return ctx.cert_self_signed(x) ? 1 : 0; + if (x.equals(issuer)) return ctx.cert_self_signed(x) ? 1 : 0; ret = checkIfIssuedBy(issuer, x); if (ret == V_OK) { /* Special case: single self signed certificate */ From bf735b4be0556e947eedac5705213b1d03d1ee01 Mon Sep 17 00:00:00 2001 From: kares Date: Wed, 20 Oct 2021 17:07:22 +0200 Subject: [PATCH 51/63] [todo] auxiliary checks aren't the same as in OpenSSL --- .../java/org/jruby/ext/openssl/x509store/StoreContext.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/jruby/ext/openssl/x509store/StoreContext.java b/src/main/java/org/jruby/ext/openssl/x509store/StoreContext.java index 8fcbbb14..24dd43da 100644 --- a/src/main/java/org/jruby/ext/openssl/x509store/StoreContext.java +++ b/src/main/java/org/jruby/ext/openssl/x509store/StoreContext.java @@ -1506,7 +1506,8 @@ private int check_purpose(X509AuxCertificate x, int purpose, int depth, byte mus * also set. */ if (depth >= num_untrusted && purpose == getParam().purpose) { - tr_ok = Trust.checkTrust(x, getParam().trust, X509_TRUST_NO_SS_COMPAT); // X509_check_trust + // TODO JOSSL auxiliary settings aren't properly implemented ... + //tr_ok = Trust.checkTrust(x, getParam().trust, X509_TRUST_NO_SS_COMPAT); // X509_check_trust } switch (tr_ok) { From 7f99d1f768182a31cf9a3df77116532d166fa7aa Mon Sep 17 00:00:00 2001 From: kares Date: Wed, 20 Oct 2021 17:17:18 +0200 Subject: [PATCH 52/63] [refactor] remove commented code --- .../java/org/jruby/ext/openssl/x509store/StoreContext.java | 7 ------- 1 file changed, 7 deletions(-) diff --git a/src/main/java/org/jruby/ext/openssl/x509store/StoreContext.java b/src/main/java/org/jruby/ext/openssl/x509store/StoreContext.java index 24dd43da..72ebbe62 100644 --- a/src/main/java/org/jruby/ext/openssl/x509store/StoreContext.java +++ b/src/main/java/org/jruby/ext/openssl/x509store/StoreContext.java @@ -2185,13 +2185,6 @@ public int call(final StoreContext context) throws Exception { if (ok == 0) return ok; } - //ok = context.checkCertificateTime(xs); - //if (ok == 0) return ok; - // - //context.currentIssuer = xi; - //context.currentCertificate = xs; - //ok = verifyCallback.call(context, 1); - //if (ok == 0) return ok; if (!internal_verify_check_cert(context, xi, xs, n)) { return 0; } From ced912a5eae1f667445a31f62ad7f9e31bbd6ace Mon Sep 17 00:00:00 2001 From: kares Date: Wed, 20 Oct 2021 17:18:27 +0200 Subject: [PATCH 53/63] [test] adjust store tests (based on OSSL updates) --- src/test/ruby/x509/test_x509store.rb | 60 ++++++++++++++++++++++------ 1 file changed, 47 insertions(+), 13 deletions(-) diff --git a/src/test/ruby/x509/test_x509store.rb b/src/test/ruby/x509/test_x509store.rb index 7ab7658a..9c82b217 100644 --- a/src/test/ruby/x509/test_x509store.rb +++ b/src/test/ruby/x509/test_x509store.rb @@ -144,12 +144,13 @@ def test_add_cert_concurrently cert_store = OpenSSL::X509::Store.new assert cert_store.add_cert(root_ca) == cert_store - begin + # NOTE: logic reverted in JOSSL 0.11.0 to match C-OpenSSL (just adds certificates wout checks) + #begin cert_store.add_cert(root_ca) - fail 'added same cert twice' - rescue OpenSSL::X509::StoreError => e - assert_equal 'cert already in hash table', e.message - end + #fail 'added same cert twice' + #rescue OpenSSL::X509::StoreError => e + #assert_equal 'cert already in hash table', e.message + #end end def test_adding_pem_to_store_like_rubygems @@ -235,7 +236,17 @@ def test_verify assert_not_equal(OpenSSL::X509::V_OK, store.error) store.add_cert(ca1_cert) - assert_equal(true, store.verify(ca2_cert)) + verify = store.verify(ca1_cert) + # TODO only works when cert_self_signed is reduced to do a EXFLAG_SI instead of EXFLAG_SS + assert_equal ["/DC=org/DC=ruby-lang/CN=CA1"], + store.chain.map { |cert| cert.subject.to_s } + assert_equal(true, verify) + + verify = store.verify(ca2_cert) + assert_equal ["/DC=org/DC=ruby-lang/CN=CA2", "/DC=org/DC=ruby-lang/CN=CA1"], + store.chain.map { |cert| cert.subject.to_s } + assert_equal(true, verify) + assert_equal(OpenSSL::X509::V_OK, store.error) assert_equal("ok", store.error_string) chain = store.chain @@ -306,9 +317,18 @@ def test_verify store.add_crl(crl1) # revoke no cert store.add_crl(crl2) # revoke ee2_cert assert_equal(true, store.verify(ca1_cert)) + assert_equal ["/DC=org/DC=ruby-lang/CN=CA1"], + store.chain.map { |cert| cert.subject.to_s } + assert_equal(true, store.verify(ca2_cert)) - assert_equal(true, store.verify(ee1_cert, [ca2_cert])) - assert_equal(false, store.verify(ee2_cert, [ca2_cert])) + assert_equal ["/DC=org/DC=ruby-lang/CN=CA2", "/DC=org/DC=ruby-lang/CN=CA1"], + store.chain.map { |cert| cert.subject.to_s } + + verify = store.verify(ee1_cert, [ca2_cert]) + assert_equal(true, verify) + + verify = store.verify(ee2_cert, [ca2_cert]) + assert_equal(false, verify) store = OpenSSL::X509::Store.new store.purpose = OpenSSL::X509::PURPOSE_ANY @@ -316,15 +336,29 @@ def test_verify store.add_cert(ca1_cert) store.add_crl(crl1_2) # revoke ca2_cert store.add_crl(crl2) # revoke ee2_cert - assert_equal(true, store.verify(ca1_cert)) - assert_equal(false, store.verify(ca2_cert)) + + verify = store.verify(ca1_cert) + assert_equal ["/DC=org/DC=ruby-lang/CN=CA1"], + store.chain.map { |cert| cert.subject.to_s } + assert_equal(true, verify) + + verify = store.verify(ca2_cert) + assert_equal ["/DC=org/DC=ruby-lang/CN=CA2", "/DC=org/DC=ruby-lang/CN=CA1"], + store.chain.map { |cert| cert.subject.to_s } + assert_equal(false, verify) + assert_equal(true, store.verify(ee1_cert, [ca2_cert]), "This test is expected to be success with OpenSSL 0.9.7c or later.") assert_equal(false, store.verify(ee2_cert, [ca2_cert])) - store.flags = - OpenSSL::X509::V_FLAG_CRL_CHECK|OpenSSL::X509::V_FLAG_CRL_CHECK_ALL - assert_equal(true, store.verify(ca1_cert)) + store.flags = OpenSSL::X509::V_FLAG_CRL_CHECK | OpenSSL::X509::V_FLAG_CRL_CHECK_ALL + + verify = store.verify(ca1_cert) + assert_equal ["/DC=org/DC=ruby-lang/CN=CA1"], + store.chain.map { |cert| cert.subject.to_s } + puts "verify(ca1_cert) #{verify} - store.error: #{store.error} (#{store.error_string})" + assert_equal(true, verify) + assert_equal(false, store.verify(ca2_cert)) assert_equal(false, store.verify(ee1_cert, [ca2_cert])) assert_equal(false, store.verify(ee2_cert, [ca2_cert])) From 42a4b6a4f321dd465388d9cd8fc0b9a53747b5d2 Mon Sep 17 00:00:00 2001 From: kares Date: Wed, 20 Oct 2021 17:19:15 +0200 Subject: [PATCH 54/63] [test] use fixed time so tests pass in few months --- src/test/ruby/ssl/test_ssl.rb | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/test/ruby/ssl/test_ssl.rb b/src/test/ruby/ssl/test_ssl.rb index 43232524..ef088dec 100644 --- a/src/test/ruby/ssl/test_ssl.rb +++ b/src/test/ruby/ssl/test_ssl.rb @@ -374,6 +374,9 @@ def test_set_custom_params -----END CERTIFICATE----- EOF + require 'time' + VERIFY_EXPIRED_TIME = Time.parse("2021/10/20 09:10:00") + def test_cert_verify_expired1_lets_encrypt_cross_signed_root # reproducer for https://github.com/jruby/jruby-openssl/issues/236 # @@ -392,6 +395,7 @@ def test_cert_verify_expired1_lets_encrypt_cross_signed_root ] cert_store = OpenSSL::X509::Store.new + cert_store.time = VERIFY_EXPIRED_TIME root_bundle.each { |cert| cert_store.add_cert cert } # the endpoint will send the leaf node + these two intermediate certs @@ -449,6 +453,7 @@ def test_cert_verify_expired2_lets_encrypt_cross_signed_intermediate ] cert_store = OpenSSL::X509::Store.new + cert_store.time = VERIFY_EXPIRED_TIME root_bundle.each { |cert| cert_store.add_cert cert } # cross-signed cert is sent from the server : @@ -484,6 +489,7 @@ def test_cert_verify_expired0_lets_encrypt # base_line ] cert_store = OpenSSL::X509::Store.new + cert_store.time = VERIFY_EXPIRED_TIME root_bundle.each { |cert| cert_store.add_cert cert } chain = [ @@ -501,6 +507,15 @@ def test_cert_verify_expired0_lets_encrypt # base_line "/C=US/O=Let's Encrypt/CN=R3", "/C=US/O=Internet Security Research Group/CN=ISRG Root X1"], cert_store.chain.map { |cert| cert.subject.to_s } + + cert_store = OpenSSL::X509::Store.new + cert_store.time = VERIFY_EXPIRED_TIME + cert_store.add_cert root_bundle[1] # only the expired one + + ok = cert_store.verify(LEAF_CERTIFICATE, chain) + + assert !ok + assert_equal 'unable to get issuer certificate', cert_store.error_string end end From b3428ab6267bb4774f91a5537cb3d76625d85c71 Mon Sep 17 00:00:00 2001 From: kares Date: Wed, 20 Oct 2021 17:44:40 +0200 Subject: [PATCH 55/63] [build] update to 1.8 (drop support for Java 7) --- Mavenfile | 4 ++-- pom.xml | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Mavenfile b/Mavenfile index e81ff72d..1d95b07b 100644 --- a/Mavenfile +++ b/Mavenfile @@ -7,7 +7,7 @@ distribution_management do repository :id => :ossrh, :url => 'https://oss.sonatype.org/service/local/staging/deploy/maven2/' end -java_target = '1.7' +java_target = '1.8' gen_sources = '${basedir}/target/generated-sources' # hard-coded in AnnotationBinder plugin( 'org.codehaus.mojo:exec-maven-plugin', '1.3.2' ) do @@ -46,7 +46,7 @@ plugin( 'org.codehaus.mojo:build-helper-maven-plugin', '1.9' ) do end plugin( :compiler, '3.1', - :source => '1.7', :target => java_target, + :source => '1.8', :target => java_target, :encoding => 'UTF-8', :debug => true, :showWarnings => true, :showDeprecation => true, :excludes => [ 'module-info.java' ], diff --git a/pom.xml b/pom.xml index c58a99b9..3ee9078d 100644 --- a/pom.xml +++ b/pom.xml @@ -209,7 +209,7 @@ DO NOT MODIFIY - GENERATED CODE java compile - -Djruby.bytecode.version=1.7 + -Djruby.bytecode.version=1.8 -classpath org.jruby.anno.InvokerGenerator @@ -261,8 +261,8 @@ DO NOT MODIFIY - GENERATED CODE - 1.7 - 1.7 + 1.8 + 1.8 UTF-8 true true @@ -368,7 +368,7 @@ DO NOT MODIFIY - GENERATED CODE 3.8.1 9 - 1.7 + 1.8 9 module-info.java From 494c299c394bc30fe8c44796b0577e9b92601412 Mon Sep 17 00:00:00 2001 From: kares Date: Wed, 20 Oct 2021 17:45:23 +0200 Subject: [PATCH 56/63] [release] prepare a 0.11 release candidate --- lib/jopenssl/version.rb | 2 +- pom.xml | 16 ++++++++-------- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/lib/jopenssl/version.rb b/lib/jopenssl/version.rb index 20a253d5..8544f144 100644 --- a/lib/jopenssl/version.rb +++ b/lib/jopenssl/version.rb @@ -1,5 +1,5 @@ module JOpenSSL - VERSION = '0.10.8.dev' + VERSION = '0.11.0.cr1' BOUNCY_CASTLE_VERSION = '1.68' end diff --git a/pom.xml b/pom.xml index 3ee9078d..9a31a517 100644 --- a/pom.xml +++ b/pom.xml @@ -11,7 +11,7 @@ DO NOT MODIFIY - GENERATED CODE 4.0.0 rubygems jruby-openssl - 0.10.8.dev-SNAPSHOT + 0.11.0.cr1-SNAPSHOT gem JRuby OpenSSL JRuby-OpenSSL is an add-on gem for JRuby that emulates the Ruby OpenSSL native library. @@ -61,17 +61,17 @@ DO NOT MODIFIY - GENERATED CODE 1.68 - 1.0.3 + ${maven.test.skip} + ${bc.versions} + 1.1.8 -W0 9.1.17.0 - 1.1.8 - ${maven.test.skip} - src/test/ruby/**/test_*.rb - 1.0.3 9.1.17.0 - false + 1.0.3 + 1.0.3 pom.xml - ${bc.versions} + false + src/test/ruby/**/test_*.rb From 898f3c9b4364811850b7b97e3c3cc860c5daac62 Mon Sep 17 00:00:00 2001 From: kares Date: Mon, 25 Oct 2021 08:27:17 +0200 Subject: [PATCH 57/63] support a jruby.openssl.x509.store.verify flag --- .../java/org/jruby/ext/openssl/x509store/StoreContext.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/jruby/ext/openssl/x509store/StoreContext.java b/src/main/java/org/jruby/ext/openssl/x509store/StoreContext.java index 72ebbe62..e4c1a906 100644 --- a/src/main/java/org/jruby/ext/openssl/x509store/StoreContext.java +++ b/src/main/java/org/jruby/ext/openssl/x509store/StoreContext.java @@ -823,7 +823,11 @@ public int verifyCertificate() throws Exception { return ret; } - private static final boolean VERIFY_LEGACY = Boolean.getBoolean("verify_legacy"); + private static final boolean VERIFY_LEGACY; + static { + String verify = SafePropertyAccessor.getProperty("jruby.openssl.x509.store.verify"); + VERIFY_LEGACY = "legacy".equals(verify); + } private int verifyChain() throws Exception { if (VERIFY_LEGACY) return verify_chain_legacy(); From 43ec397af59a221351ef72250482264443a04f08 Mon Sep 17 00:00:00 2001 From: kares Date: Mon, 25 Oct 2021 08:28:37 +0200 Subject: [PATCH 58/63] [refactor] hide internal deprecated method --- src/main/java/org/jruby/ext/openssl/x509store/StoreContext.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/jruby/ext/openssl/x509store/StoreContext.java b/src/main/java/org/jruby/ext/openssl/x509store/StoreContext.java index e4c1a906..a129ac9d 100644 --- a/src/main/java/org/jruby/ext/openssl/x509store/StoreContext.java +++ b/src/main/java/org/jruby/ext/openssl/x509store/StoreContext.java @@ -1319,7 +1319,7 @@ int build_chain() throws Exception { } @Deprecated // legacy find_issuer - public X509AuxCertificate findIssuer(final List certs, + private X509AuxCertificate findIssuer(final List certs, final X509AuxCertificate cert, final boolean check_time) throws Exception { for ( X509AuxCertificate issuer : certs ) { if ( checkIssued.call(this, cert, issuer) != 0 ) { From 6d6012264496ab7eef36c029aee172d4dd4a66c0 Mon Sep 17 00:00:00 2001 From: kares Date: Mon, 25 Oct 2021 09:03:02 +0200 Subject: [PATCH 59/63] Revert "[build] update to 1.8 (drop support for Java 7)" This reverts commit b3428ab6267bb4774f91a5537cb3d76625d85c71. --- Mavenfile | 4 ++-- pom.xml | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Mavenfile b/Mavenfile index 1d95b07b..e81ff72d 100644 --- a/Mavenfile +++ b/Mavenfile @@ -7,7 +7,7 @@ distribution_management do repository :id => :ossrh, :url => 'https://oss.sonatype.org/service/local/staging/deploy/maven2/' end -java_target = '1.8' +java_target = '1.7' gen_sources = '${basedir}/target/generated-sources' # hard-coded in AnnotationBinder plugin( 'org.codehaus.mojo:exec-maven-plugin', '1.3.2' ) do @@ -46,7 +46,7 @@ plugin( 'org.codehaus.mojo:build-helper-maven-plugin', '1.9' ) do end plugin( :compiler, '3.1', - :source => '1.8', :target => java_target, + :source => '1.7', :target => java_target, :encoding => 'UTF-8', :debug => true, :showWarnings => true, :showDeprecation => true, :excludes => [ 'module-info.java' ], diff --git a/pom.xml b/pom.xml index 9a31a517..9c77df72 100644 --- a/pom.xml +++ b/pom.xml @@ -209,7 +209,7 @@ DO NOT MODIFIY - GENERATED CODE java compile - -Djruby.bytecode.version=1.8 + -Djruby.bytecode.version=1.7 -classpath org.jruby.anno.InvokerGenerator @@ -261,8 +261,8 @@ DO NOT MODIFIY - GENERATED CODE - 1.8 - 1.8 + 1.7 + 1.7 UTF-8 true true @@ -368,7 +368,7 @@ DO NOT MODIFIY - GENERATED CODE 3.8.1 9 - 1.8 + 1.7 9 module-info.java From 885e04f218ca25551d4e77790f0e34fdea600791 Mon Sep 17 00:00:00 2001 From: kares Date: Mon, 25 Oct 2021 09:04:40 +0200 Subject: [PATCH 60/63] Revert "[release] prepare a 0.11 release candidate" This reverts commit 494c299c394bc30fe8c44796b0577e9b92601412. --- lib/jopenssl/version.rb | 2 +- pom.xml | 16 ++++++++-------- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/lib/jopenssl/version.rb b/lib/jopenssl/version.rb index 8544f144..20a253d5 100644 --- a/lib/jopenssl/version.rb +++ b/lib/jopenssl/version.rb @@ -1,5 +1,5 @@ module JOpenSSL - VERSION = '0.11.0.cr1' + VERSION = '0.10.8.dev' BOUNCY_CASTLE_VERSION = '1.68' end diff --git a/pom.xml b/pom.xml index 9c77df72..c58a99b9 100644 --- a/pom.xml +++ b/pom.xml @@ -11,7 +11,7 @@ DO NOT MODIFIY - GENERATED CODE 4.0.0 rubygems jruby-openssl - 0.11.0.cr1-SNAPSHOT + 0.10.8.dev-SNAPSHOT gem JRuby OpenSSL JRuby-OpenSSL is an add-on gem for JRuby that emulates the Ruby OpenSSL native library. @@ -61,17 +61,17 @@ DO NOT MODIFIY - GENERATED CODE 1.68 - ${maven.test.skip} - ${bc.versions} - 1.1.8 + 1.0.3 -W0 9.1.17.0 - 9.1.17.0 + 1.1.8 + ${maven.test.skip} + src/test/ruby/**/test_*.rb 1.0.3 - 1.0.3 - pom.xml + 9.1.17.0 false - src/test/ruby/**/test_*.rb + pom.xml + ${bc.versions} From d9cd9776abc2fb2cfc73b80e8873df123d833338 Mon Sep 17 00:00:00 2001 From: kares Date: Mon, 25 Oct 2021 09:43:43 +0200 Subject: [PATCH 61/63] S: support a jruby.openssl.x509.store.verify flag --- src/main/java/org/jruby/ext/openssl/x509store/StoreContext.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/jruby/ext/openssl/x509store/StoreContext.java b/src/main/java/org/jruby/ext/openssl/x509store/StoreContext.java index a129ac9d..ba1e9385 100644 --- a/src/main/java/org/jruby/ext/openssl/x509store/StoreContext.java +++ b/src/main/java/org/jruby/ext/openssl/x509store/StoreContext.java @@ -41,7 +41,6 @@ import java.util.HashSet; import java.util.LinkedList; import java.util.List; -import java.util.ListIterator; import java.util.Set; import org.bouncycastle.asn1.ASN1InputStream; @@ -49,6 +48,7 @@ import org.bouncycastle.asn1.ASN1Sequence; import org.jruby.ext.openssl.OpenSSL; import org.jruby.ext.openssl.SecurityHelper; +import org.jruby.util.SafePropertyAccessor; import static org.jruby.ext.openssl.x509store.X509Error.addError; import static org.jruby.ext.openssl.x509store.X509Utils.*; From d80e8ecb38f3e596b5ceb05eef98fa00064a801d Mon Sep 17 00:00:00 2001 From: kares Date: Mon, 25 Oct 2021 09:59:32 +0200 Subject: [PATCH 62/63] [refactor] rename StoreContext fields for easier following of OpenSSL internals --- .../org/jruby/ext/openssl/SSLContext.java | 6 +- .../ext/openssl/x509store/StoreContext.java | 147 +++++++++--------- 2 files changed, 76 insertions(+), 77 deletions(-) diff --git a/src/main/java/org/jruby/ext/openssl/SSLContext.java b/src/main/java/org/jruby/ext/openssl/SSLContext.java index 618f7b16..97c2ee5c 100644 --- a/src/main/java/org/jruby/ext/openssl/SSLContext.java +++ b/src/main/java/org/jruby/ext/openssl/SSLContext.java @@ -1109,14 +1109,14 @@ private void verifyChain(final StoreContext storeContext) throws CertificateExce ok = storeContext.verifyCertificate(); } catch (Exception e) { - internalContext.setLastVerifyResult(storeContext.error); - if ( storeContext.error == X509Utils.V_OK ) { + internalContext.setLastVerifyResult(storeContext.getError()); + if ( storeContext.getError() == X509Utils.V_OK ) { internalContext.setLastVerifyResult(X509Utils.V_ERR_CERT_REJECTED); } throw new CertificateException("certificate verify failed", e); } - internalContext.setLastVerifyResult(storeContext.error); + internalContext.setLastVerifyResult(storeContext.getError()); if ( ok == 0 ) { throw new CertificateException("certificate verify failed"); } diff --git a/src/main/java/org/jruby/ext/openssl/x509store/StoreContext.java b/src/main/java/org/jruby/ext/openssl/x509store/StoreContext.java index ba1e9385..2f5c1467 100644 --- a/src/main/java/org/jruby/ext/openssl/x509store/StoreContext.java +++ b/src/main/java/org/jruby/ext/openssl/x509store/StoreContext.java @@ -64,13 +64,14 @@ public class StoreContext { private final Store store; - X509AuxCertificate certificate; + X509AuxCertificate cert; List untrusted; List crls; - public VerifyParameter verifyParameter; + private VerifyParameter verifyParameter; + private List extraData; - public List otherContext; + private List otherContext; public StoreContext(final Store store) { this.store = store; @@ -93,21 +94,19 @@ interface CheckPolicyFunction extends Function1 {} public boolean isValid; - private int num_untrusted; // lastUntrusted in the chain + private int num_untrusted; // last_untrusted (OpenSSL 1.0.2) in the chain private ArrayList chain; private PolicyTree tree; - private int explicitPolicy; + private int explicit_policy; - public int error; - public int errorDepth; + int error; + int error_depth; - X509AuxCertificate currentCertificate; - X509AuxCertificate currentIssuer; - X509CRL currentCRL; - - List extraData; + X509AuxCertificate current_cert; + X509AuxCertificate current_issuer; + X509CRL current_crl; private StoreContext parent; // NOTE: not implemented - dummy null for now @@ -294,7 +293,7 @@ public static X509AuxCertificate ensureAux(final X509Certificate input) { */ public int init(X509AuxCertificate cert, List untrusted_chain) { // int ret = 1; - this.certificate = cert; + this.cert = cert; this.untrusted = untrusted_chain; this.crls = null; this.num_untrusted = 0; @@ -302,11 +301,11 @@ public int init(X509AuxCertificate cert, List untrusted_chai this.isValid = false; this.chain = null; this.error = V_OK; - this.explicitPolicy = 0; - this.errorDepth = 0; - this.currentCertificate = null; - this.currentIssuer = null; - this.currentCRL = null; + this.explicit_policy = 0; + this.error_depth = 0; + this.current_cert = null; + this.current_issuer = null; + this.current_crl = null; this.tree = null; this.parent = null; @@ -455,18 +454,18 @@ public void setError(int s) { * c: X509_STORE_CTX_get_error_depth */ public int getErrorDepth() { - return errorDepth; + return error_depth; } /** * c: X509_STORE_CTX_get_current_cert */ public X509AuxCertificate getCurrentCertificate() { - return currentCertificate; + return current_cert; } public X509CRL getCurrentCRL() { - return currentCRL; + return current_crl; } /** @@ -488,11 +487,11 @@ public List getFirstChain() { * c: X509_STORE_CTX_set_cert */ public void setCertificate(X509AuxCertificate x) { - this.certificate = x; + this.cert = x; } public void setCertificate(X509Certificate x) { - this.certificate = ensureAux(x); + this.cert = ensureAux(x); } /** @@ -677,7 +676,7 @@ PolicyTree getPolicyTree() { * c: X509_STORE_CTX_get_explicit_policy */ public int getExplicitPolicy() { - return explicitPolicy; + return explicit_policy; } /** @@ -782,7 +781,7 @@ private List matchCachedCertObjectsFromStore(final Name name * c: int X509_verify_cert(X509_STORE_CTX *ctx) */ public int verifyCertificate() throws Exception { - if (certificate == null) { + if (cert == null) { addError(X509_R_NO_CERT_SET_FOR_US_TO_VERIFY); this.error = V_ERR_INVALID_CALL; return -1; @@ -803,7 +802,7 @@ public int verifyCertificate() throws Exception { */ //if (chain == null) { chain = new ArrayList(8); - chain.add(certificate); + chain.add(cert); num_untrusted = 1; //} @@ -890,8 +889,8 @@ int verify_chain_legacy() throws Exception { xtmp = p_xtmp[0]; if ( ok <= 0 || ! x.equals(xtmp) ) { error = X509Utils.V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT; - currentCertificate = x; - errorDepth = i-1; + current_cert = x; + error_depth = i-1; bad_chain = 1; ok = verifyCallback.call(this, ZERO); if ( ok == 0 ) return ok; @@ -941,15 +940,15 @@ int verify_chain_legacy() throws Exception { } else { error = X509Utils.V_ERR_UNABLE_TO_GET_ISSUER_CERT; } - currentCertificate = x; + current_cert = x; } else { chain.add(chain_ss); num++; num_untrusted = num; - currentCertificate = chain_ss; + current_cert = chain_ss; error = X509Utils.V_ERR_SELF_SIGNED_CERT_IN_CHAIN; } - errorDepth = num - 1; + error_depth = num - 1; bad_chain = 1; int ok = verifyCallback.call(this, ZERO); if ( ok == 0 ) return ok; @@ -1394,15 +1393,15 @@ public int checkChainExtensions() throws Exception { x = chain.get(i); if ( (verifyParameter.flags & X509Utils.V_FLAG_IGNORE_CRITICAL) == 0 && unhandledCritical(x) ) { error = X509Utils.V_ERR_UNHANDLED_CRITICAL_EXTENSION; - errorDepth = i; - currentCertificate = x; + error_depth = i; + current_cert = x; ok = verifyCallback.call(this, ZERO); if ( ok == 0 ) return ok; } if ( allow_proxy_certs == 0 && x.getExtensionValue("1.3.6.1.5.5.7.1.14") != null ) { error = X509Utils.V_ERR_PROXY_CERTIFICATES_NOT_ALLOWED; - errorDepth = i; - currentCertificate = x; + error_depth = i; + current_cert = x; ok = verifyCallback.call(this, ZERO); if ( ok == 0 ) return ok; } @@ -1435,8 +1434,8 @@ public int checkChainExtensions() throws Exception { break; } if(ret == 0) { - errorDepth = i; - currentCertificate = x; + error_depth = i; + current_cert = x; ok = verifyCallback.call(this, ZERO); if ( ok == 0 ) return ok; } @@ -1444,8 +1443,8 @@ public int checkChainExtensions() throws Exception { ret = Purpose.checkPurpose(x,verifyParameter.purpose, must_be_ca > 0 ? 1 : 0); if(ret == 0 || ((verifyParameter.flags & X509Utils.V_FLAG_X509_STRICT) != 0 && ret != 1)) { error = X509Utils.V_ERR_INVALID_PURPOSE; - errorDepth = i; - currentCertificate = x; + error_depth = i; + current_cert = x; ok = verifyCallback.call(this, ZERO); if(ok == 0) { return ok; @@ -1455,8 +1454,8 @@ public int checkChainExtensions() throws Exception { if(i > 1 && x.getBasicConstraints() != -1 && x.getBasicConstraints() != Integer.MAX_VALUE && (i > (x.getBasicConstraints() + proxy_path_length + 1))) { error = X509Utils.V_ERR_PATH_LENGTH_EXCEEDED; - errorDepth = i; - currentCertificate = x; + error_depth = i; + current_cert = x; ok = verifyCallback.call(this, ZERO); if ( ok == 0 ) return ok; } @@ -1467,8 +1466,8 @@ public int checkChainExtensions() throws Exception { int pcpathlen = ((ASN1Integer)pci.getObjectAt(0)).getValue().intValue(); if(i > pcpathlen) { error = X509Utils.V_ERR_PROXY_PATH_LENGTH_EXCEEDED; - errorDepth = i; - currentCertificate = x; + error_depth = i; + current_cert = x; ok = verifyCallback.call(this, ZERO); if ( ok == 0 ) return ok; } @@ -1684,8 +1683,8 @@ private int checkTrust() throws Exception { if ( ok == X509Utils.X509_TRUST_TRUSTED ) { return 1; // X509_TRUST_TRUSTED } - errorDepth = 1; - currentCertificate = x; + error_depth = 1; + current_cert = x; if ( ok == X509Utils.X509_TRUST_REJECTED ) { error = X509Utils.V_ERR_CERT_REJECTED; } else { @@ -1814,10 +1813,10 @@ public int checkCertificate() throws Exception { final X509CRL[] crl = new X509CRL[1]; X509AuxCertificate x; int ok, cnum; - cnum = errorDepth; + cnum = error_depth; x = chain.get(cnum); - currentCertificate = x; - currentIssuer = null; + current_cert = x; + current_issuer = null; if (x.getExtensionValue("1.3.6.1.5.5.7.1.14") != null) return 1; // (x.getExFlags() & EXFLAG_PROXY) != 0 @@ -1825,17 +1824,17 @@ public int checkCertificate() throws Exception { if ( ok == 0 ) { error = X509Utils.V_ERR_UNABLE_TO_GET_CRL; ok = verifyCallback.call(this, ZERO); - currentCRL = null; + current_crl = null; return ok; } - currentCRL = crl[0]; + current_crl = crl[0]; ok = checkCRL.call(this, crl[0]); if ( ok == 0 ) { - currentCRL = null; + current_crl = null; return ok; } ok = certificateCRL.call(this, crl[0], x); - currentCRL = null; + current_crl = null; return ok; } @@ -1843,7 +1842,7 @@ public int checkCertificate() throws Exception { private boolean check_crl_time(X509CRL crl, final boolean notify) throws Exception { final Date pTime; - if (notify) this.currentCRL = crl; + if (notify) this.current_crl = crl; if ((getParam().flags & V_FLAG_USE_CHECK_TIME) != 0) { pTime = getParam().checkTime; @@ -1882,14 +1881,14 @@ private boolean check_crl_time(X509CRL crl, final boolean notify) throws Excepti } } - if (notify) this.currentCRL = null; + if (notify) this.current_crl = null; return true; } @Deprecated // legacy check_crl_time private int checkCRLTime(X509CRL crl, int notify) throws Exception { - currentCRL = crl; + current_crl = crl; final Date pTime; if ((getParam().flags & V_FLAG_USE_CHECK_TIME) != 0) { pTime = getParam().checkTime; @@ -1910,7 +1909,7 @@ private int checkCRLTime(X509CRL crl, int notify) throws Exception { } } - currentCRL = null; + current_crl = null; return 1; } @@ -1960,8 +1959,8 @@ private X509AuxCertificate lookup_cert_match(X509AuxCertificate x) throws Except * Returns 0 to abort verification with an error, non-zero to continue. */ private int verify_cb_cert(X509AuxCertificate x, int depth, int err) throws Exception { - this.errorDepth = depth; - this.currentCertificate = x != null ? x : chain.get(depth); + this.error_depth = depth; + this.current_cert = x != null ? x : chain.get(depth); if (err != V_OK) this.error = err; return verifyCallback.call(this, 0); // ctx->verify_cb(0, ctx) } @@ -2034,8 +2033,8 @@ public int call(StoreContext context, X509AuxCertificate cert, X509AuxCertificat return 0; } context.error = ret; - context.currentCertificate = cert; - context.currentIssuer = issuer; + context.current_cert = cert; + context.current_issuer = issuer; return context.verifyCallback.call(context, ZERO); } @@ -2078,7 +2077,7 @@ private int internal_verify() throws Exception { } n--; - errorDepth = n; + error_depth = n; xs = chain.get(n); } @@ -2129,9 +2128,9 @@ private static boolean internal_verify_check_cert( * Signal success at this depth. However, the previous error (if any) * is retained. */ - ctx.currentIssuer = xi; - ctx.currentCertificate = xs; - ctx.errorDepth = n; + ctx.current_issuer = xi; + ctx.current_cert = xs; + ctx.error_depth = n; if (ctx.verifyCallback.call(ctx, 1) == 0) return false; @@ -2159,7 +2158,7 @@ public int call(final StoreContext context) throws Exception { Store.VerifyCallbackFunction verifyCallback = context.verifyCallback; int n = context.chain.size(); - context.errorDepth = n - 1; + context.error_depth = n - 1; n--; X509AuxCertificate xi = context.chain.get(n); X509AuxCertificate xs = null; @@ -2170,21 +2169,21 @@ public int call(final StoreContext context) throws Exception { } else { if (n <= 0) { context.error = X509Utils.V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE; - context.currentCertificate = xi; + context.current_cert = xi; ok = verifyCallback.call(context, ZERO); return ok; } else { n--; - context.errorDepth = n; + context.error_depth = n; xs = context.chain.get(n); } } while (n >= 0) { - context.errorDepth = n; + context.error_depth = n; if (!X509_verify(xs, xi.getPublicKey())) { context.error = X509Utils.V_ERR_CERT_SIGNATURE_FAILURE; - context.currentCertificate = xs; + context.current_cert = xs; ok = verifyCallback.call(context, ZERO); if (ok == 0) return ok; } @@ -2221,7 +2220,7 @@ public int call(final StoreContext ctx) throws Exception { last = 0; } for ( int i=0; i<=last; i++ ) { - ctx.errorDepth = i; + ctx.error_depth = i; int ok = ctx.checkCertificate(); // check_cert(ctx); if (ok == 0) return 0; } @@ -2259,12 +2258,12 @@ public int call(final StoreContext context, final X509CRL[] crls, X509AuxCertifi /* Check CRL validity */ private int check_crl(X509CRL crl) throws Exception { final X509AuxCertificate issuer; - int cnum = this.errorDepth; + int cnum = this.error_depth; int chnum = this.chain.size() - 1; /* if we have an alternative CRL issuer cert use that */ - if (this.currentIssuer != null) - issuer = this.currentIssuer; + if (this.current_issuer != null) + issuer = this.current_issuer; /* * Else find CRL issuer: if not last certificate then issuer is next * certificate in chain. @@ -2344,7 +2343,7 @@ public int call(final StoreContext ctx, final X509CRL crl) throws Exception { final static Store.CheckCRLFunction check_crl_legacy = new Store.CheckCRLFunction() { public int call(final StoreContext context, final X509CRL crl) throws Exception { - final int errorDepth = context.errorDepth; + final int errorDepth = context.error_depth; final int lastInChain = context.chain.size() - 1; int ok; From e7799fcf74b420d85872dc4e3d8f73cb620e3d8f Mon Sep 17 00:00:00 2001 From: kares Date: Mon, 25 Oct 2021 10:48:22 +0200 Subject: [PATCH 63/63] [test] missing certificate files for added tests --- .../letsencrypt/isrg-root-x1-cross-signed.pem | 31 +++++++++++++++++++ src/test/ruby/ssl/letsencrypt/isrgrootx1.pem | 31 +++++++++++++++++++ .../lets-encrypt-r3-cross-signed.pem | 26 ++++++++++++++++ .../ruby/ssl/letsencrypt/lets-encrypt-r3.pem | 30 ++++++++++++++++++ 4 files changed, 118 insertions(+) create mode 100644 src/test/ruby/ssl/letsencrypt/isrg-root-x1-cross-signed.pem create mode 100644 src/test/ruby/ssl/letsencrypt/isrgrootx1.pem create mode 100644 src/test/ruby/ssl/letsencrypt/lets-encrypt-r3-cross-signed.pem create mode 100644 src/test/ruby/ssl/letsencrypt/lets-encrypt-r3.pem diff --git a/src/test/ruby/ssl/letsencrypt/isrg-root-x1-cross-signed.pem b/src/test/ruby/ssl/letsencrypt/isrg-root-x1-cross-signed.pem new file mode 100644 index 00000000..a788a405 --- /dev/null +++ b/src/test/ruby/ssl/letsencrypt/isrg-root-x1-cross-signed.pem @@ -0,0 +1,31 @@ +-----BEGIN CERTIFICATE----- +MIIFYDCCBEigAwIBAgIQQAF3ITfU6UK47naqPGQKtzANBgkqhkiG9w0BAQsFADA/ +MSQwIgYDVQQKExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4xFzAVBgNVBAMT +DkRTVCBSb290IENBIFgzMB4XDTIxMDEyMDE5MTQwM1oXDTI0MDkzMDE4MTQwM1ow +TzELMAkGA1UEBhMCVVMxKTAnBgNVBAoTIEludGVybmV0IFNlY3VyaXR5IFJlc2Vh +cmNoIEdyb3VwMRUwEwYDVQQDEwxJU1JHIFJvb3QgWDEwggIiMA0GCSqGSIb3DQEB +AQUAA4ICDwAwggIKAoICAQCt6CRz9BQ385ueK1coHIe+3LffOJCMbjzmV6B493XC +ov71am72AE8o295ohmxEk7axY/0UEmu/H9LqMZshftEzPLpI9d1537O4/xLxIZpL +wYqGcWlKZmZsj348cL+tKSIG8+TA5oCu4kuPt5l+lAOf00eXfJlII1PoOK5PCm+D +LtFJV4yAdLbaL9A4jXsDcCEbdfIwPPqPrt3aY6vrFk/CjhFLfs8L6P+1dy70sntK +4EwSJQxwjQMpoOFTJOwT2e4ZvxCzSow/iaNhUd6shweU9GNx7C7ib1uYgeGJXDR5 +bHbvO5BieebbpJovJsXQEOEO3tkQjhb7t/eo98flAgeYjzYIlefiN5YNNnWe+w5y +sR2bvAP5SQXYgd0FtCrWQemsAXaVCg/Y39W9Eh81LygXbNKYwagJZHduRze6zqxZ +Xmidf3LWicUGQSk+WT7dJvUkyRGnWqNMQB9GoZm1pzpRboY7nn1ypxIFeFntPlF4 +FQsDj43QLwWyPntKHEtzBRL8xurgUBN8Q5N0s8p0544fAQjQMNRbcTa0B7rBMDBc +SLeCO5imfWCKoqMpgsy6vYMEG6KDA0Gh1gXxG8K28Kh8hjtGqEgqiNx2mna/H2ql +PRmP6zjzZN7IKw0KKP/32+IVQtQi0Cdd4Xn+GOdwiK1O5tmLOsbdJ1Fu/7xk9TND +TwIDAQABo4IBRjCCAUIwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYw +SwYIKwYBBQUHAQEEPzA9MDsGCCsGAQUFBzAChi9odHRwOi8vYXBwcy5pZGVudHJ1 +c3QuY29tL3Jvb3RzL2RzdHJvb3RjYXgzLnA3YzAfBgNVHSMEGDAWgBTEp7Gkeyxx ++tvhS5B1/8QVYIWJEDBUBgNVHSAETTBLMAgGBmeBDAECATA/BgsrBgEEAYLfEwEB +ATAwMC4GCCsGAQUFBwIBFiJodHRwOi8vY3BzLnJvb3QteDEubGV0c2VuY3J5cHQu +b3JnMDwGA1UdHwQ1MDMwMaAvoC2GK2h0dHA6Ly9jcmwuaWRlbnRydXN0LmNvbS9E +U1RST09UQ0FYM0NSTC5jcmwwHQYDVR0OBBYEFHm0WeZ7tuXkAXOACIjIGlj26Ztu +MA0GCSqGSIb3DQEBCwUAA4IBAQAKcwBslm7/DlLQrt2M51oGrS+o44+/yQoDFVDC +5WxCu2+b9LRPwkSICHXM6webFGJueN7sJ7o5XPWioW5WlHAQU7G75K/QosMrAdSW +9MUgNTP52GE24HGNtLi1qoJFlcDyqSMo59ahy2cI2qBDLKobkx/J3vWraV0T9VuG +WCLKTVXkcGdtwlfFRjlBz4pYg1htmf5X6DYO8A4jqv2Il9DjXA6USbW1FzXSLr9O +he8Y4IWS6wY7bCkjCWDcRQJMEhg76fsO3txE+FiYruq9RUWhiF1myv4Q6W+CyBFC +Dfvp7OOGAN6dEOM4+qR9sdjoSYKEBpsr6GtPAQw4dy753ec5 +-----END CERTIFICATE----- diff --git a/src/test/ruby/ssl/letsencrypt/isrgrootx1.pem b/src/test/ruby/ssl/letsencrypt/isrgrootx1.pem new file mode 100644 index 00000000..b85c8037 --- /dev/null +++ b/src/test/ruby/ssl/letsencrypt/isrgrootx1.pem @@ -0,0 +1,31 @@ +-----BEGIN CERTIFICATE----- +MIIFazCCA1OgAwIBAgIRAIIQz7DSQONZRGPgu2OCiwAwDQYJKoZIhvcNAQELBQAw +TzELMAkGA1UEBhMCVVMxKTAnBgNVBAoTIEludGVybmV0IFNlY3VyaXR5IFJlc2Vh +cmNoIEdyb3VwMRUwEwYDVQQDEwxJU1JHIFJvb3QgWDEwHhcNMTUwNjA0MTEwNDM4 +WhcNMzUwNjA0MTEwNDM4WjBPMQswCQYDVQQGEwJVUzEpMCcGA1UEChMgSW50ZXJu +ZXQgU2VjdXJpdHkgUmVzZWFyY2ggR3JvdXAxFTATBgNVBAMTDElTUkcgUm9vdCBY +MTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAK3oJHP0FDfzm54rVygc +h77ct984kIxuPOZXoHj3dcKi/vVqbvYATyjb3miGbESTtrFj/RQSa78f0uoxmyF+ +0TM8ukj13Xnfs7j/EvEhmkvBioZxaUpmZmyPfjxwv60pIgbz5MDmgK7iS4+3mX6U +A5/TR5d8mUgjU+g4rk8Kb4Mu0UlXjIB0ttov0DiNewNwIRt18jA8+o+u3dpjq+sW +T8KOEUt+zwvo/7V3LvSye0rgTBIlDHCNAymg4VMk7BPZ7hm/ELNKjD+Jo2FR3qyH +B5T0Y3HsLuJvW5iB4YlcNHlsdu87kGJ55tukmi8mxdAQ4Q7e2RCOFvu396j3x+UC +B5iPNgiV5+I3lg02dZ77DnKxHZu8A/lJBdiB3QW0KtZB6awBdpUKD9jf1b0SHzUv +KBds0pjBqAlkd25HN7rOrFleaJ1/ctaJxQZBKT5ZPt0m9STJEadao0xAH0ahmbWn +OlFuhjuefXKnEgV4We0+UXgVCwOPjdAvBbI+e0ocS3MFEvzG6uBQE3xDk3SzynTn +jh8BCNAw1FtxNrQHusEwMFxIt4I7mKZ9YIqioymCzLq9gwQbooMDQaHWBfEbwrbw +qHyGO0aoSCqI3Haadr8faqU9GY/rOPNk3sgrDQoo//fb4hVC1CLQJ13hef4Y53CI +rU7m2Ys6xt0nUW7/vGT1M0NPAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNV +HRMBAf8EBTADAQH/MB0GA1UdDgQWBBR5tFnme7bl5AFzgAiIyBpY9umbbjANBgkq +hkiG9w0BAQsFAAOCAgEAVR9YqbyyqFDQDLHYGmkgJykIrGF1XIpu+ILlaS/V9lZL +ubhzEFnTIZd+50xx+7LSYK05qAvqFyFWhfFQDlnrzuBZ6brJFe+GnY+EgPbk6ZGQ +3BebYhtF8GaV0nxvwuo77x/Py9auJ/GpsMiu/X1+mvoiBOv/2X/qkSsisRcOj/KK +NFtY2PwByVS5uCbMiogziUwthDyC3+6WVwW6LLv3xLfHTjuCvjHIInNzktHCgKQ5 +ORAzI4JMPJ+GslWYHb4phowim57iaztXOoJwTdwJx4nLCgdNbOhdjsnvzqvHu7Ur +TkXWStAmzOVyyghqpZXjFaH3pO3JLF+l+/+sKAIuvtd7u+Nxe5AW0wdeRlN8NwdC +jNPElpzVmbUq4JUagEiuTDkHzsxHpFKVK7q4+63SM1N95R1NbdWhscdCb+ZAJzVc +oyi3B43njTOQ5yOf+1CceWxG1bQVs5ZufpsMljq4Ui0/1lvh+wjChP4kqKOJ2qxq +4RgqsahDYVvTH9w7jXbyLeiNdd8XM2w9U/t7y0Ff/9yi0GE44Za4rF2LN9d11TPA +mRGunUHBcnWEvgJBQl9nJEiU0Zsnvgc/ubhPgXRR4Xq37Z0j4r7g1SgEEzwxA57d +emyPxgcYxn/eR44/KJ4EBs+lVDR3veyJm+kXQ99b21/+jh5Xos1AnX5iItreGCc= +-----END CERTIFICATE----- diff --git a/src/test/ruby/ssl/letsencrypt/lets-encrypt-r3-cross-signed.pem b/src/test/ruby/ssl/letsencrypt/lets-encrypt-r3-cross-signed.pem new file mode 100644 index 00000000..1d82449a --- /dev/null +++ b/src/test/ruby/ssl/letsencrypt/lets-encrypt-r3-cross-signed.pem @@ -0,0 +1,26 @@ +-----BEGIN CERTIFICATE----- +MIIEZTCCA02gAwIBAgIQQAF1BIMUpMghjISpDBbN3zANBgkqhkiG9w0BAQsFADA/ +MSQwIgYDVQQKExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4xFzAVBgNVBAMT +DkRTVCBSb290IENBIFgzMB4XDTIwMTAwNzE5MjE0MFoXDTIxMDkyOTE5MjE0MFow +MjELMAkGA1UEBhMCVVMxFjAUBgNVBAoTDUxldCdzIEVuY3J5cHQxCzAJBgNVBAMT +AlIzMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuwIVKMz2oJTTDxLs +jVWSw/iC8ZmmekKIp10mqrUrucVMsa+Oa/l1yKPXD0eUFFU1V4yeqKI5GfWCPEKp +Tm71O8Mu243AsFzzWTjn7c9p8FoLG77AlCQlh/o3cbMT5xys4Zvv2+Q7RVJFlqnB +U840yFLuta7tj95gcOKlVKu2bQ6XpUA0ayvTvGbrZjR8+muLj1cpmfgwF126cm/7 +gcWt0oZYPRfH5wm78Sv3htzB2nFd1EbjzK0lwYi8YGd1ZrPxGPeiXOZT/zqItkel +/xMY6pgJdz+dU/nPAeX1pnAXFK9jpP+Zs5Od3FOnBv5IhR2haa4ldbsTzFID9e1R +oYvbFQIDAQABo4IBaDCCAWQwEgYDVR0TAQH/BAgwBgEB/wIBADAOBgNVHQ8BAf8E +BAMCAYYwSwYIKwYBBQUHAQEEPzA9MDsGCCsGAQUFBzAChi9odHRwOi8vYXBwcy5p +ZGVudHJ1c3QuY29tL3Jvb3RzL2RzdHJvb3RjYXgzLnA3YzAfBgNVHSMEGDAWgBTE +p7Gkeyxx+tvhS5B1/8QVYIWJEDBUBgNVHSAETTBLMAgGBmeBDAECATA/BgsrBgEE +AYLfEwEBATAwMC4GCCsGAQUFBwIBFiJodHRwOi8vY3BzLnJvb3QteDEubGV0c2Vu +Y3J5cHQub3JnMDwGA1UdHwQ1MDMwMaAvoC2GK2h0dHA6Ly9jcmwuaWRlbnRydXN0 +LmNvbS9EU1RST09UQ0FYM0NSTC5jcmwwHQYDVR0OBBYEFBQusxe3WFbLrlAJQOYf +r52LFMLGMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjANBgkqhkiG9w0B +AQsFAAOCAQEA2UzgyfWEiDcx27sT4rP8i2tiEmxYt0l+PAK3qB8oYevO4C5z70kH +ejWEHx2taPDY/laBL21/WKZuNTYQHHPD5b1tXgHXbnL7KqC401dk5VvCadTQsvd8 +S8MXjohyc9z9/G2948kLjmE6Flh9dDYrVYA9x2O+hEPGOaEOa1eePynBgPayvUfL +qjBstzLhWVQLGAkXXmNs+5ZnPBxzDJOLxhF2JIbeQAcH5H0tZrUlo5ZYyOqA7s9p +O5b85o3AM/OJ+CktFBQtfvBhcJVd9wvlwPsk+uyOy2HI7mNxKKgsBTt375teA2Tw +UdHkhVNcsAKX1H7GNNLOEADksd86wuoXvg== +-----END CERTIFICATE----- diff --git a/src/test/ruby/ssl/letsencrypt/lets-encrypt-r3.pem b/src/test/ruby/ssl/letsencrypt/lets-encrypt-r3.pem new file mode 100644 index 00000000..43b222a6 --- /dev/null +++ b/src/test/ruby/ssl/letsencrypt/lets-encrypt-r3.pem @@ -0,0 +1,30 @@ +-----BEGIN CERTIFICATE----- +MIIFFjCCAv6gAwIBAgIRAJErCErPDBinU/bWLiWnX1owDQYJKoZIhvcNAQELBQAw +TzELMAkGA1UEBhMCVVMxKTAnBgNVBAoTIEludGVybmV0IFNlY3VyaXR5IFJlc2Vh +cmNoIEdyb3VwMRUwEwYDVQQDEwxJU1JHIFJvb3QgWDEwHhcNMjAwOTA0MDAwMDAw +WhcNMjUwOTE1MTYwMDAwWjAyMQswCQYDVQQGEwJVUzEWMBQGA1UEChMNTGV0J3Mg +RW5jcnlwdDELMAkGA1UEAxMCUjMwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK +AoIBAQC7AhUozPaglNMPEuyNVZLD+ILxmaZ6QoinXSaqtSu5xUyxr45r+XXIo9cP +R5QUVTVXjJ6oojkZ9YI8QqlObvU7wy7bjcCwXPNZOOftz2nwWgsbvsCUJCWH+jdx +sxPnHKzhm+/b5DtFUkWWqcFTzjTIUu61ru2P3mBw4qVUq7ZtDpelQDRrK9O8Zutm +NHz6a4uPVymZ+DAXXbpyb/uBxa3Shlg9F8fnCbvxK/eG3MHacV3URuPMrSXBiLxg +Z3Vms/EY96Jc5lP/Ooi2R6X/ExjqmAl3P51T+c8B5fWmcBcUr2Ok/5mzk53cU6cG +/kiFHaFpriV1uxPMUgP17VGhi9sVAgMBAAGjggEIMIIBBDAOBgNVHQ8BAf8EBAMC +AYYwHQYDVR0lBBYwFAYIKwYBBQUHAwIGCCsGAQUFBwMBMBIGA1UdEwEB/wQIMAYB +Af8CAQAwHQYDVR0OBBYEFBQusxe3WFbLrlAJQOYfr52LFMLGMB8GA1UdIwQYMBaA +FHm0WeZ7tuXkAXOACIjIGlj26ZtuMDIGCCsGAQUFBwEBBCYwJDAiBggrBgEFBQcw +AoYWaHR0cDovL3gxLmkubGVuY3Iub3JnLzAnBgNVHR8EIDAeMBygGqAYhhZodHRw +Oi8veDEuYy5sZW5jci5vcmcvMCIGA1UdIAQbMBkwCAYGZ4EMAQIBMA0GCysGAQQB +gt8TAQEBMA0GCSqGSIb3DQEBCwUAA4ICAQCFyk5HPqP3hUSFvNVneLKYY611TR6W +PTNlclQtgaDqw+34IL9fzLdwALduO/ZelN7kIJ+m74uyA+eitRY8kc607TkC53wl +ikfmZW4/RvTZ8M6UK+5UzhK8jCdLuMGYL6KvzXGRSgi3yLgjewQtCPkIVz6D2QQz +CkcheAmCJ8MqyJu5zlzyZMjAvnnAT45tRAxekrsu94sQ4egdRCnbWSDtY7kh+BIm +lJNXoB1lBMEKIq4QDUOXoRgffuDghje1WrG9ML+Hbisq/yFOGwXD9RiX8F6sw6W4 +avAuvDszue5L3sz85K+EC4Y/wFVDNvZo4TYXao6Z0f+lQKc0t8DQYzk1OXVu8rp2 +yJMC6alLbBfODALZvYH7n7do1AZls4I9d1P4jnkDrQoxB3UqQ9hVl3LEKQ73xF1O +yK5GhDDX8oVfGKF5u+decIsH4YaTw7mP3GFxJSqv3+0lUFJoi5Lc5da149p90Ids +hCExroL1+7mryIkXPeFM5TgO9r0rvZaBFOvV2z0gp35Z0+L4WPlbuEjN/lxPFin+ +HlUjr8gRsI3qfJOQFy/9rKIJR0Y/8Omwt/8oTWgy1mdeHmmjk7j1nYsvC9JSQ6Zv +MldlTTKB3zhThV1+XWYp6rjd5JW1zbVWEkLNxE7GJThEUG3szgBVGP7pSWTUTsqX +nLRbwHOoq7hHwg== +-----END CERTIFICATE-----