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 <rsalz@openssl.org>
This commit is contained in:
parent
ad64a69e02
commit
338fb1688f
5 changed files with 85 additions and 3 deletions
|
@ -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
|
||||
|
@ -1322,7 +1324,7 @@ void ERR_load_X509_strings(void);
|
|||
# define X509_R_WRONG_LOOKUP_TYPE 112
|
||||
# define X509_R_WRONG_TYPE 122
|
||||
|
||||
#ifdef __cplusplus
|
||||
# ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
# endif
|
||||
#endif
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/* 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"},
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 */
|
||||
|
|
Loading…
Reference in a new issue