krb5/krb5-pkinit-cms2.patch

291 lines
12 KiB
Diff

When verifying signed-data, use the OpenSSL CMS APIs if we're building with a
version of OpenSSL which supplies them (1.0.0 or later). Revised proposal for
RT#6851.
diff --git a/src/plugins/preauth/pkinit/pkinit_crypto_openssl.c b/src/plugins/preauth/pkinit/pkinit_crypto_openssl.c
index bb8f036..6aedec4 100644
--- a/src/plugins/preauth/pkinit/pkinit_crypto_openssl.c
+++ b/src/plugins/preauth/pkinit/pkinit_crypto_openssl.c
@@ -41,6 +41,34 @@
#include "pkinit_crypto_openssl.h"
+#if OPENSSL_VERSION_NUMBER >= 0x10000000L
+#include <openssl/cms.h>
+#define pkinit_CMS_free1_crls(_sk_x509crl) sk_X509_CRL_free((_sk_x509crl))
+#define pkinit_CMS_free1_certs(_sk_x509) sk_X509_free((_sk_x509))
+#define pkinit_CMS_SignerInfo_get_cert(_cms,_si,_x509_pp) CMS_SignerInfo_get0_algs(_si,NULL,_x509_pp,NULL,NULL)
+#else
+#define pkinit_CMS_free1_crls(_stack_of_x509crls) /* don't free these CRLs */
+#define pkinit_CMS_free1_certs(_stack_of_x509certs) /* don't free these certs */
+#define CMS_NO_SIGNER_CERT_VERIFY PKCS7_NOVERIFY
+#define CMS_NOATTR PKCS7_NOATTR
+#define CMS_ContentInfo PKCS7
+#define CMS_SignerInfo PKCS7_SIGNER_INFO
+#define d2i_CMS_ContentInfo d2i_PKCS7
+#define CMS_get0_type(_p7) ((_p7)->type)
+#define CMS_get0_content(_p7) (&((_p7)->d.other->value.octet_string))
+#define CMS_set1_signers_certs(_p7,_stack_of_x509,_uint)
+#define CMS_get0_SignerInfos PKCS7_get_signer_info
+#define stack_st_CMS_SignerInfo stack_st_PKCS7_SIGNER_INFO
+#undef sk_CMS_SignerInfo_value
+#define sk_CMS_SignerInfo_value sk_PKCS7_SIGNER_INFO_value
+#define CMS_get0_eContentType(_p7) (_p7->d.sign->contents->type)
+#define CMS_verify PKCS7_verify
+#define CMS_get1_crls(_p7) (_p7->d.sign->crl)
+#define CMS_get1_certs(_p7) (_p7->d.sign->cert)
+#define CMS_ContentInfo_free(_p7) PKCS7_free(_p7)
+#define pkinit_CMS_SignerInfo_get_cert(_p7,_si,_x509_pp) (*_x509_pp) = PKCS7_cert_from_signer_info(_p7,_si)
+#endif
+
static struct pkcs11_errstrings {
short code;
char *text;
@@ -1127,21 +1155,25 @@ cms_signeddata_verify(krb5_context context,
int *is_signed)
{
krb5_error_code retval = KRB5KDC_ERR_PREAUTH_FAILED;
- PKCS7 *p7 = NULL;
+ CMS_ContentInfo *cms = NULL;
BIO *out = NULL;
- int flags = PKCS7_NOVERIFY;
+ int flags = CMS_NO_SIGNER_CERT_VERIFY;
unsigned int i = 0;
unsigned int vflags = 0, size = 0;
const unsigned char *p = signed_data;
- STACK_OF(PKCS7_SIGNER_INFO) *si_sk = NULL;
- PKCS7_SIGNER_INFO *si = NULL;
+ STACK_OF(CMS_SignerInfo) *si_sk = NULL;
+ CMS_SignerInfo *si = NULL;
X509 *x = NULL;
X509_STORE *store = NULL;
X509_STORE_CTX cert_ctx;
+ STACK_OF(X509) *signerCerts = NULL;
STACK_OF(X509) *intermediateCAs = NULL;
+ STACK_OF(X509_CRL) *signerRevoked = NULL;
STACK_OF(X509_CRL) *revoked = NULL;
STACK_OF(X509) *verified_chain = NULL;
ASN1_OBJECT *oid = NULL;
+ const ASN1_OBJECT *type = NULL, *etype = NULL;
+ ASN1_OCTET_STRING **octets;
krb5_external_principal_identifier **krb5_verified_chain = NULL;
krb5_data *authz = NULL;
char buf[DN_BUF_LEN];
@@ -1157,8 +1189,8 @@ cms_signeddata_verify(krb5_context context,
if (oid == NULL)
goto cleanup;
- /* decode received PKCS7 message */
- if ((p7 = d2i_PKCS7(NULL, &p, (int)signed_data_len)) == NULL) {
+ /* decode received CMS message */
+ if ((cms = d2i_CMS_ContentInfo(NULL, &p, (int)signed_data_len)) == NULL) {
unsigned long err = ERR_peek_error();
krb5_set_error_message(context, retval, "%s\n",
ERR_error_string(err, NULL));
@@ -1168,37 +1200,39 @@ cms_signeddata_verify(krb5_context context,
}
/* Handle the case in pkinit anonymous where we get unsigned data. */
- if (is_signed && !OBJ_cmp(p7->type, oid)) {
+ type = CMS_get0_type(cms);
+ if (is_signed && !OBJ_cmp(type, oid)) {
unsigned char *d;
*is_signed = 0;
- if (p7->d.other->type != V_ASN1_OCTET_STRING) {
+ octets = CMS_get0_content(cms);
+ if (!octets || ((*octets)->type != V_ASN1_OCTET_STRING)) {
retval = KRB5KDC_ERR_PREAUTH_FAILED;
krb5_set_error_message(context, KRB5KDC_ERR_PREAUTH_FAILED,
"Invalid pkinit packet: octet string "
"expected");
goto cleanup;
}
- *data_len = ASN1_STRING_length(p7->d.other->value.octet_string);
+ *data_len = ASN1_STRING_length(*octets);
d = malloc(*data_len);
if (d == NULL) {
retval = ENOMEM;
goto cleanup;
}
- memcpy(d, ASN1_STRING_data(p7->d.other->value.octet_string),
+ memcpy(d, ASN1_STRING_data(*octets),
*data_len);
*data = d;
goto out;
} else {
- /* Verify that the received message is PKCS7 SignedData message. */
- if (OBJ_obj2nid(p7->type) != NID_pkcs7_signed) {
- pkiDebug("Expected id-signedData PKCS7 msg (received type = %d)\n",
- OBJ_obj2nid(p7->type));
+ /* Verify that the received message is CMS SignedData message. */
+ if (OBJ_obj2nid(type) != NID_pkcs7_signed) {
+ pkiDebug("Expected id-signedData CMS msg (received type = %d)\n",
+ OBJ_obj2nid(type));
krb5_set_error_message(context, retval, "wrong oid\n");
goto cleanup;
}
}
- /* setup to verify X509 certificate used to sign PKCS7 message */
+ /* setup to verify X509 certificate used to sign CMS message */
if (!(store = X509_STORE_new()))
goto cleanup;
@@ -1210,37 +1244,41 @@ cms_signeddata_verify(krb5_context context,
X509_STORE_set_verify_cb_func(store, openssl_callback_ignore_crls);
X509_STORE_set_flags(store, vflags);
- /* get the signer's information from the PKCS7 message */
- if ((si_sk = PKCS7_get_signer_info(p7)) == NULL)
+ /* get the signer's information from the CMS message */
+ CMS_set1_signers_certs(cms, NULL, 0);
+ if ((si_sk = CMS_get0_SignerInfos(cms)) == NULL)
goto cleanup;
- if ((si = sk_PKCS7_SIGNER_INFO_value(si_sk, 0)) == NULL)
+ if ((si = sk_CMS_SignerInfo_value(si_sk, 0)) == NULL)
goto cleanup;
- if ((x = PKCS7_cert_from_signer_info(p7, si)) == NULL)
+ pkinit_CMS_SignerInfo_get_cert(cms, si, &x);
+ if (x == NULL)
goto cleanup;
/* create available CRL information (get local CRLs and include CRLs
- * received in the PKCS7 message
+ * received in the CMS message
*/
+ signerRevoked = CMS_get1_crls(cms);
if (idctx->revoked == NULL)
- revoked = p7->d.sign->crl;
- else if (p7->d.sign->crl == NULL)
+ revoked = signerRevoked;
+ else if (signerRevoked == NULL)
revoked = idctx->revoked;
else {
size = sk_X509_CRL_num(idctx->revoked);
revoked = sk_X509_CRL_new_null();
for (i = 0; i < size; i++)
sk_X509_CRL_push(revoked, sk_X509_CRL_value(idctx->revoked, i));
- size = sk_X509_CRL_num(p7->d.sign->crl);
+ size = sk_X509_CRL_num(signerRevoked);
for (i = 0; i < size; i++)
- sk_X509_CRL_push(revoked, sk_X509_CRL_value(p7->d.sign->crl, i));
+ sk_X509_CRL_push(revoked, sk_X509_CRL_value(signerRevoked, i));
}
/* create available intermediate CAs chains (get local intermediateCAs and
- * include the CA chain received in the PKCS7 message
+ * include the CA chain received in the CMS message
*/
+ signerCerts = CMS_get1_certs(cms);
if (idctx->intermediateCAs == NULL)
- intermediateCAs = p7->d.sign->cert;
- else if (p7->d.sign->cert == NULL)
+ intermediateCAs = signerCerts;
+ else if (signerCerts == NULL)
intermediateCAs = idctx->intermediateCAs;
else {
size = sk_X509_num(idctx->intermediateCAs);
@@ -1249,9 +1287,9 @@ cms_signeddata_verify(krb5_context context,
sk_X509_push(intermediateCAs,
sk_X509_value(idctx->intermediateCAs, i));
}
- size = sk_X509_num(p7->d.sign->cert);
+ size = sk_X509_num(signerCerts);
for (i = 0; i < size; i++) {
- sk_X509_push(intermediateCAs, sk_X509_value(p7->d.sign->cert, i));
+ sk_X509_push(intermediateCAs, sk_X509_value(signerCerts, i));
}
}
@@ -1329,10 +1367,10 @@ cms_signeddata_verify(krb5_context context,
krb5_set_error_message(context, retval, "%s\n",
X509_verify_cert_error_string(j));
#ifdef DEBUG_CERTCHAIN
- size = sk_X509_num(p7->d.sign->cert);
+ size = sk_X509_num(signerCerts);
pkiDebug("received cert chain of size %d\n", size);
for (j = 0; j < size; j++) {
- X509 *tmp_cert = sk_X509_value(p7->d.sign->cert, j);
+ X509 *tmp_cert = sk_X509_value(signerCerts, j);
X509_NAME_oneline(X509_get_subject_name(tmp_cert), buf, sizeof(buf));
pkiDebug("cert #%d: %s\n", j, buf);
}
@@ -1348,11 +1386,12 @@ cms_signeddata_verify(krb5_context context,
out = BIO_new(BIO_s_mem());
if (cms_msg_type == CMS_SIGN_DRAFT9)
- flags |= PKCS7_NOATTR;
- if (PKCS7_verify(p7, NULL, store, NULL, out, flags)) {
+ flags |= CMS_NOATTR;
+ etype = CMS_get0_eContentType(cms);
+ if (CMS_verify(cms, NULL, store, NULL, out, flags)) {
int valid_oid = 0;
- if (!OBJ_cmp(p7->d.sign->contents->type, oid))
+ if (!OBJ_cmp(etype, oid))
valid_oid = 1;
else if (cms_msg_type == CMS_SIGN_DRAFT9) {
/*
@@ -1364,18 +1403,18 @@ cms_signeddata_verify(krb5_context context,
client_oid = pkinit_pkcs7type2oid(plgctx, CMS_SIGN_CLIENT);
server_oid = pkinit_pkcs7type2oid(plgctx, CMS_SIGN_SERVER);
rsa_oid = pkinit_pkcs7type2oid(plgctx, CMS_ENVEL_SERVER);
- if (!OBJ_cmp(p7->d.sign->contents->type, client_oid) ||
- !OBJ_cmp(p7->d.sign->contents->type, server_oid) ||
- !OBJ_cmp(p7->d.sign->contents->type, rsa_oid))
+ if (!OBJ_cmp(etype, client_oid) ||
+ !OBJ_cmp(etype, server_oid) ||
+ !OBJ_cmp(etype, rsa_oid))
valid_oid = 1;
}
if (valid_oid)
- pkiDebug("PKCS7 Verification successful\n");
+ pkiDebug("CMS Verification successful\n");
else {
pkiDebug("wrong oid in eContentType\n");
- print_buffer(p7->d.sign->contents->type->data,
- (unsigned int)p7->d.sign->contents->type->length);
+ print_buffer(etype->data,
+ (unsigned int)etype->length);
retval = KRB5KDC_ERR_PREAUTH_FAILED;
krb5_set_error_message(context, retval, "wrong oid\n");
goto cleanup;
@@ -1391,13 +1430,13 @@ cms_signeddata_verify(krb5_context context,
default:
retval = KRB5KDC_ERR_INVALID_SIG;
}
- pkiDebug("PKCS7 Verification failure\n");
+ pkiDebug("CMS Verification failure\n");
krb5_set_error_message(context, retval, "%s\n",
ERR_error_string(err, NULL));
goto cleanup;
}
- /* transfer the data from PKCS7 message into return buffer */
+ /* transfer the data from CMS message into return buffer */
for (size = 0;;) {
int remain;
retval = ENOMEM;
@@ -1452,12 +1491,16 @@ cleanup:
BIO_free(out);
if (store != NULL)
X509_STORE_free(store);
- if (p7 != NULL) {
- if (idctx->intermediateCAs != NULL && p7->d.sign->cert)
+ if (cms != NULL) {
+ if (signerCerts != NULL)
+ pkinit_CMS_free1_certs(signerCerts);
+ if (idctx->intermediateCAs != NULL && signerCerts)
sk_X509_free(intermediateCAs);
- if (idctx->revoked != NULL && p7->d.sign->crl)
+ if (signerRevoked != NULL)
+ pkinit_CMS_free1_crls(signerRevoked);
+ if (idctx->revoked != NULL && signerRevoked)
sk_X509_CRL_free(revoked);
- PKCS7_free(p7);
+ CMS_ContentInfo_free(cms);
}
if (verified_chain != NULL)
sk_X509_pop_free(verified_chain, X509_free);