Commit 338fb168 authored by Richard Levitte's avatar Richard Levitte
Browse files

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: default avatarRich Salz <rsalz@openssl.org>
parent ad64a69e
Loading
Loading
Loading
Loading
+4 −2
Original line number Diff line number Diff line
@@ -1234,6 +1234,7 @@ int X509_TRUST_get_trust(X509_TRUST *xp);
 * The following lines are auto generated by the script mkerr.pl. Any changes
 * made after this point may be overwritten when the script is next run.
 */

void ERR_load_X509_strings(void);

/* Error codes for the X509 functions. */
@@ -1241,6 +1242,7 @@ void ERR_load_X509_strings(void);
/* Function codes. */
# define X509_F_ADD_CERT_DIR                              100
# define X509_F_BY_FILE_CTRL                              101
# define X509_F_CHECK_NAME_CONSTRAINTS                    106
# define X509_F_CHECK_POLICY                              145
# define X509_F_DIR_CTRL                                  102
# define X509_F_GET_CERT_BY_SUBJECT                       103
+2 −1
Original line number Diff line number Diff line
/* crypto/x509/x509_err.c */
/* ====================================================================
 * Copyright (c) 1999-2012 The OpenSSL Project.  All rights reserved.
 * Copyright (c) 1999-2016 The OpenSSL Project.  All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
@@ -72,6 +72,7 @@
static ERR_STRING_DATA X509_str_functs[] = {
    {ERR_FUNC(X509_F_ADD_CERT_DIR), "ADD_CERT_DIR"},
    {ERR_FUNC(X509_F_BY_FILE_CTRL), "BY_FILE_CTRL"},
    {ERR_FUNC(X509_F_CHECK_NAME_CONSTRAINTS), "CHECK_NAME_CONSTRAINTS"},
    {ERR_FUNC(X509_F_CHECK_POLICY), "CHECK_POLICY"},
    {ERR_FUNC(X509_F_DIR_CTRL), "DIR_CTRL"},
    {ERR_FUNC(X509_F_GET_CERT_BY_SUBJECT), "GET_CERT_BY_SUBJECT"},
+2 −0
Original line number Diff line number Diff line
@@ -208,6 +208,8 @@ const char *X509_verify_cert_error_string(long n)
        return ("Invalid certificate verification context");
    case X509_V_ERR_STORE_LOOKUP:
        return ("Issuer certificate lookup error");
    case X509_V_ERR_PROXY_SUBJECT_NAME_VIOLATION:
        return ("proxy subject name violation");

    default:
        BIO_snprintf(buf, sizeof buf, "error number %ld", n);
+75 −0
Original line number Diff line number Diff line
@@ -742,6 +742,81 @@ 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_get_entry(tmpsubject, last_object_loc)->set
                == X509_NAME_get_entry(tmpsubject, last_object_loc - 1)->set) {
                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) {
                ctx->error = err;
                ctx->error_depth = i;
                ctx->current_cert = x;
                if (!ctx->verify_cb(0, ctx))
                    return 0;
            }
        }

        /*
         * Check against constraints for all certificates higher in chain
         * including trust anchor. Trust anchor not strictly speaking needed
+2 −0
Original line number Diff line number Diff line
@@ -392,6 +392,8 @@ void X509_STORE_CTX_set_depth(X509_STORE_CTX *ctx, int depth);
/* Issuer lookup error */
# define         X509_V_ERR_STORE_LOOKUP                         66

# define         X509_V_ERR_PROXY_SUBJECT_NAME_VIOLATION         67

/* Certificate verify flags */

/* Send issuer+subject checks to verify_cb */