From c8223538cb05e5aac6418a5ba6dc4775b7ab486b Mon Sep 17 00:00:00 2001 From: Richard Levitte Date: Sun, 19 Jun 2016 10:55:16 +0200 Subject: [PATCH] Check that the subject name in a proxy cert complies to RFC 3820 The subject name MUST be the same as the issuer name, with a single CN entry added. RT#1852 Reviewed-by: Rich Salz Reviewed-by: Stephen Henson --- crypto/x509/x509_txt.c | 2 ++ crypto/x509/x509_vfy.c | 73 ++++++++++++++++++++++++++++++++++++++ include/openssl/x509_vfy.h | 2 ++ 3 files changed, 77 insertions(+) diff --git a/crypto/x509/x509_txt.c b/crypto/x509/x509_txt.c index ae54de1c31..66e5fcd02f 100644 --- a/crypto/x509/x509_txt.c +++ b/crypto/x509/x509_txt.c @@ -167,6 +167,8 @@ const char *X509_verify_cert_error_string(long n) return ("Issuer certificate lookup error"); case X509_V_ERR_NO_VALID_SCTS: return ("Certificate Transparency required, but no valid SCTs found"); + case X509_V_ERR_PROXY_SUBJECT_NAME_VIOLATION: + return ("proxy subject name violation"); default: /* Printing an error number into a static buffer is not thread-safe */ diff --git a/crypto/x509/x509_vfy.c b/crypto/x509/x509_vfy.c index a5e77896f8..360664a813 100644 --- a/crypto/x509/x509_vfy.c +++ b/crypto/x509/x509_vfy.c @@ -558,6 +558,79 @@ static int check_name_constraints(X509_STORE_CTX *ctx) /* Ignore self issued certs unless last in chain */ if (i && (x->ex_flags & EXFLAG_SI)) continue; + + /* + * Proxy certificates policy has an extra constraint, where the + * certificate subject MUST be the issuer with a single CN entry + * added. + * (RFC 3820: 3.4, 4.1.3 (a)(4)) + */ + if (x->ex_flags & EXFLAG_PROXY) { + X509_NAME *tmpsubject = X509_get_subject_name(x); + X509_NAME *tmpissuer = X509_get_issuer_name(x); + X509_NAME_ENTRY *tmpentry = NULL; + int last_object_nid = 0; + int err = X509_V_OK; + int last_object_loc = X509_NAME_entry_count(tmpsubject) - 1; + + /* Check that there are at least two RDNs */ + if (last_object_loc < 1) { + err = X509_V_ERR_PROXY_SUBJECT_NAME_VIOLATION; + goto proxy_name_done; + } + + /* + * Check that there is exactly one more RDN in subject as + * there is in issuer. + */ + if (X509_NAME_entry_count(tmpsubject) + != X509_NAME_entry_count(tmpissuer) + 1) { + err = X509_V_ERR_PROXY_SUBJECT_NAME_VIOLATION; + goto proxy_name_done; + } + + /* + * Check that the last subject component isn't part of a + * multivalued RDN + */ + if (X509_NAME_ENTRY_set(X509_NAME_get_entry(tmpsubject, + last_object_loc)) + == X509_NAME_ENTRY_set(X509_NAME_get_entry(tmpsubject, + last_object_loc - 1))) { + err = X509_V_ERR_PROXY_SUBJECT_NAME_VIOLATION; + goto proxy_name_done; + } + + /* + * Check that the last subject RDN is a commonName, and that + * all the previous RDNs match the issuer exactly + */ + tmpsubject = X509_NAME_dup(tmpsubject); + if (tmpsubject == NULL) { + X509err(X509_F_CHECK_NAME_CONSTRAINTS, ERR_R_MALLOC_FAILURE); + ctx->error = X509_V_ERR_OUT_OF_MEM; + return 0; + } + + tmpentry = + X509_NAME_delete_entry(tmpsubject, last_object_loc); + last_object_nid = + OBJ_obj2nid(X509_NAME_ENTRY_get_object(tmpentry)); + + if (last_object_nid != NID_commonName + || X509_NAME_cmp(tmpsubject, tmpissuer) != 0) { + err = X509_V_ERR_PROXY_SUBJECT_NAME_VIOLATION; + } + + X509_NAME_ENTRY_free(tmpentry); + X509_NAME_free(tmpsubject); + + proxy_name_done: + if (err != X509_V_OK + && !verify_cb_cert(ctx, x, i, err)) + return 0; + } + /* * Check against constraints for all certificates higher in chain * including trust anchor. Trust anchor not strictly speaking needed diff --git a/include/openssl/x509_vfy.h b/include/openssl/x509_vfy.h index f012265573..4e44e1daea 100644 --- a/include/openssl/x509_vfy.h +++ b/include/openssl/x509_vfy.h @@ -165,6 +165,8 @@ void X509_STORE_CTX_set_depth(X509_STORE_CTX *ctx, int depth); /* Certificate transparency */ # define X509_V_ERR_NO_VALID_SCTS 71 +# define X509_V_ERR_PROXY_SUBJECT_NAME_VIOLATION 72 + /* Certificate verify flags */ # if OPENSSL_API_COMPAT < 0x10100000L -- 2.25.1