-
Notifications
You must be signed in to change notification settings - Fork 287
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
ssl_cert_username_cea: Use CertificateExactAssertion as username #202
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -268,6 +268,7 @@ openssl_iostream_set(struct ssl_iostream *ssl_io, | |
set->verbose_invalid_cert || | ||
event_want_debug(ssl_io->event); | ||
ssl_io->allow_invalid_cert = set->allow_invalid_cert; | ||
ssl_io->username_cea = set->cert_username_cea; | ||
return 0; | ||
} | ||
|
||
|
@@ -811,6 +812,86 @@ openssl_iostream_get_peer_name(struct ssl_iostream *ssl_io) | |
#endif | ||
i_assert(x509 != NULL); | ||
|
||
if (ssl_io->username_cea) { | ||
|
||
ASN1_INTEGER *serialNumber; | ||
X509_NAME *issuer; | ||
BIGNUM *bn; | ||
char *decimal; | ||
BIO *bio; | ||
|
||
bio = BIO_new(BIO_s_mem()); | ||
if (!bio) { | ||
name = NULL; | ||
goto end; | ||
} | ||
|
||
BIO_puts(bio, "{ serialNumber "); | ||
|
||
serialNumber = X509_get_serialNumber(x509); | ||
if (!serialNumber) { | ||
BIO_free(bio); | ||
name = NULL; | ||
goto end; | ||
} | ||
|
||
bn = ASN1_INTEGER_to_BN(serialNumber, NULL); | ||
if (!bn) { | ||
BIO_free(bio); | ||
name = NULL; | ||
goto end; | ||
} | ||
|
||
decimal = BN_bn2dec(bn); | ||
if (!decimal) { | ||
BIO_free(bio); | ||
BN_free(bn); | ||
name = NULL; | ||
goto end; | ||
} | ||
|
||
BIO_puts(bio, decimal); | ||
|
||
OPENSSL_free(decimal); | ||
BN_free(bn); | ||
|
||
BIO_puts(bio, ", issuer rdnSequence:\""); | ||
|
||
issuer = X509_get_issuer_name(x509); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This seems like it should be escaping There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Let me check this.
Felt a bit weird to mix them up, but can do. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Checked - escaping is unnecessary (and would break the string), as the rfc2253 already escapes the issuer name as described below: There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Looking at the code, using a BIO is the simplest way. If I had to try and convert it to t_strdup_printf(), we would still have the same extraction of the fields, then we would need to t_malloc0() the BIO, then assemble the string, then get rid of the temporary t_malloc0. Letting openssl do all the work is way cleaner. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
I think the certificates could still be evil and have There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
That's not possible in this case. RFC4523 appendix A.1 describes a string that consists of the serial number (in a safe format), concatenated with the issuer DN encoded as per rfc2253 (in a safe format). If the issuer wasn't safely escaped already, someone could create a malicious certificate that contained the target desired issuer with a 0x00 character in it, and then fake the identity of another certificate. This is prevented because rfc2253 mandates that the distinguished name be escaped. Quoting from rfc2253 to show we are escaped already:
Any attempt to modify the CEA string outside that described by the RFC above means the string will not match with or interoperate with other software. |
||
if (!issuer) { | ||
BIO_free(bio); | ||
name = NULL; | ||
goto end; | ||
} | ||
|
||
X509_NAME_print_ex(bio, issuer, 0, XN_FLAG_RFC2253); | ||
|
||
BIO_puts(bio, "\" }"); | ||
|
||
len = BIO_pending(bio); | ||
if (len < 0) { | ||
name = NULL; | ||
} | ||
else { | ||
name = t_malloc0(len + 1); | ||
if (BIO_read(bio, name, len) != len) { | ||
name = NULL; | ||
} | ||
else if (strlen(name) != (size_t)len) { | ||
/* NUL characters in name. Someone's trying to fake | ||
being another user? Don't allow it. */ | ||
name = NULL; | ||
} | ||
else { | ||
name[len] = 0; | ||
} | ||
} | ||
|
||
BIO_free(bio); | ||
|
||
goto end; | ||
} | ||
|
||
len = X509_NAME_get_text_by_NID(X509_get_subject_name(x509), | ||
ssl_io->username_nid, NULL, 0); | ||
if (len < 0) | ||
|
@@ -827,6 +908,8 @@ openssl_iostream_get_peer_name(struct ssl_iostream *ssl_io) | |
name = NULL; | ||
} | ||
} | ||
|
||
end: | ||
X509_free(x509); | ||
|
||
return name; | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Probably could be configured via
ssl_cert_username_field = CertificateExactAssertion
? Otherwise there's a conflict with these two settings.Although I don't know, how common is this use case anyway? Maybe this would be better as a more generic setting using variables, like:
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I considered it originally, however ssl_cert_username_field refers to rdns inside the subject of the certificate, while CertificateExactAssertion refers to a property of the whole certificate. It felt cleaner to have a separate directive.
ssl_cert_username_cea wins.
The problem with the variable approach is that the RFC definition of CertificateExactAssertion is precise on the format of both the serialNumber and the issuer.
The XN_FLAG_RFC2253 flag gives the correct format, while X509_NAME_oneline uses a legacy format.
I ran into the same problem when I did Apache httpd's support, the definitions of the existing variables weren't tight enough.