From 85c727f35167830a84223aa4eb46c7f7031acb53 Mon Sep 17 00:00:00 2001 From: Nalin Dahyabhai Date: Mon, 27 Sep 2010 23:41:21 -0400 Subject: [PATCH 011/150] - pull some of the matching data --- src/plugins/preauth/pkinit/pkinit_crypto_nss.c | 152 ++++++++++++++++++++---- 1 files changed, 129 insertions(+), 23 deletions(-) diff --git a/src/plugins/preauth/pkinit/pkinit_crypto_nss.c b/src/plugins/preauth/pkinit/pkinit_crypto_nss.c index 1dc4674..4b75d07 100644 --- a/src/plugins/preauth/pkinit/pkinit_crypto_nss.c +++ b/src/plugins/preauth/pkinit/pkinit_crypto_nss.c @@ -1015,7 +1015,7 @@ crypto_cert_iteration_begin(krb5_context context, pkinit_cert_iter_handle *iter_handle) { PLArenaPool *pool; - struct _pkinit_cert_iter_info *info; + struct _pkinit_cert_iter_info *handle; if (CERT_LIST_EMPTY(id_cryptoctx->id_certs)) { return ENOENT; } @@ -1023,15 +1023,15 @@ crypto_cert_iteration_begin(krb5_context context, if (pool == NULL) { return ENOMEM; } - info = PORT_ArenaZAlloc(pool, sizeof(*info)); - if (info == NULL) { + handle = PORT_ArenaZAlloc(pool, sizeof(*handle)); + if (handle == NULL) { PORT_FreeArena(pool, PR_TRUE); return ENOMEM; } - info->pool = pool; - info->id_cryptoctx = id_cryptoctx; - info->node = CERT_LIST_HEAD(info->id_cryptoctx->id_certs); - *iter_handle = info; + handle->pool = pool; + handle->id_cryptoctx = id_cryptoctx; + handle->node = CERT_LIST_HEAD(handle->id_cryptoctx->id_certs); + *iter_handle = handle; return 0; } @@ -1040,9 +1040,7 @@ krb5_error_code crypto_cert_iteration_end(krb5_context context, pkinit_cert_iter_handle iter_handle) { - struct _pkinit_cert_iter_info *info; - info = iter_handle; - PORT_FreeArena(info->pool, PR_TRUE); + PORT_FreeArena(iter_handle->pool, PR_TRUE); return 0; } @@ -1053,35 +1051,142 @@ crypto_cert_iteration_next(krb5_context context, pkinit_cert_handle *cert_handle) { CERTCertListNode *node; - struct _pkinit_cert_iter_info *info; - struct _pkinit_cert_info *cert; - info = iter_handle; /* Find the next node. */ - node = CERT_LIST_NEXT(info->node); - if (CERT_LIST_END(node, info->id_cryptoctx->id_certs)) { + node = CERT_LIST_NEXT(iter_handle->node); + if (CERT_LIST_END(node, iter_handle->id_cryptoctx->id_certs)) { + /* No more entries. */ *cert_handle = NULL; return ENOENT; } /* Try to store cert info. */ - cert = PORT_ArenaZAlloc(info->pool, sizeof(*cert)); - if (cert == NULL) { + *cert_handle = PORT_ArenaZAlloc(iter_handle->pool, + sizeof(**cert_handle)); + if (*cert_handle == NULL) { return ENOMEM; } /* Record that we iterated. */ - info->node = node; - cert->id_cryptoctx = info->id_cryptoctx; - cert->cert = node->cert; - *cert_handle = cert; + iter_handle->node = node; + (*cert_handle)->id_cryptoctx = iter_handle->id_cryptoctx; + (*cert_handle)->cert = node->cert; return 0; } /* Read names, key usage, and extended key usage from the cert. */ +static unsigned int +cert_get_ku_bits(krb5_context context, pkinit_cert_handle cert_handle) +{ + unsigned int ku = 0; + if (cert_handle->cert->keyUsage & KU_DIGITAL_SIGNATURE) { + ku |= PKINIT_KU_DIGITALSIGNATURE; + } + if (cert_handle->cert->keyUsage & KU_KEY_ENCIPHERMENT) { + ku |= PKINIT_KU_KEYENCIPHERMENT; + } + return ku; +} +static unsigned char oid_pkinit_key_purpose_client_bytes[] = + {0x2b, 0x06, 0x01, 0x05, 0x02, 0x03, 0x04}; +static SECItem pkinit_kp_client = { + .data = oid_pkinit_key_purpose_client_bytes, + .len = 7, +}; +static unsigned char oid_pkinit_key_purpose_kdc_bytes[] = + {0x2b, 0x06, 0x01, 0x05, 0x02, 0x03, 0x05}; +static SECItem pkinit_kp_kdc = { + .data = oid_pkinit_key_purpose_kdc_bytes, + .len = 7, +}; +static unsigned char oid_ms_sc_login_key_purpose[] = + {0x2b, 0x06, 0x01, 0x04, 0x01, 0x82, 0x37, 0x14, 0x02, 0x02}; +static SECItem pkinit_kp_mssclogin = { + .data = oid_ms_sc_login_key_purpose, + .len = 10, +}; +static unsigned int +cert_get_eku_bits(krb5_context context, pkinit_cert_handle cert_handle, int kdc) +{ + PLArenaPool *pool; + CERTCertExtension *ext; + SECItem **oids; + SECOidData *oid, *clientauth, *email; + int i; + unsigned int eku; + + /* Find the extended key usage extension. */ + ext = NULL; + oid = SECOID_FindOIDByTag(SEC_OID_X509_EXT_KEY_USAGE); + for (i = 0; + (cert_handle->cert->extensions != NULL) && + (cert_handle->cert->extensions[i] != NULL); + i++) { + ext = cert_handle->cert->extensions[i]; + if (SECITEM_ItemsAreEqual(&ext->id, &oid->oid)) { + break; + } + ext = NULL; + } + if (ext == NULL) { + /* No extendedKeyUsage extension present. */ + return 0; + } + + /* Look up the well-known OIDs. */ + clientauth = SECOID_FindOIDByTag(SEC_OID_EXT_KEY_USAGE_CLIENT_AUTH); + email = SECOID_FindOIDByTag(SEC_OID_EXT_KEY_USAGE_EMAIL_PROTECT); + + /* Decode the list of EKU values. */ + pool = PORT_NewArena(sizeof(double)); + oids = NULL; + if (SEC_ASN1DecodeItem(pool, &oids, + SEC_SequenceOfObjectIDTemplate, + &ext->value) != SECSuccess) { + PORT_FreeArena(pool, PR_TRUE); + return 0; + } + eku = 0; + for (i = 0; (oids != NULL) && (oids[i] != NULL); i++) { + if (SECITEM_ItemsAreEqual(oids[i], &clientauth->oid)) { + eku |= PKINIT_EKU_CLIENTAUTH; + } + if (SECITEM_ItemsAreEqual(oids[i], &email->oid)) { + eku |= PKINIT_EKU_EMAILPROTECTION; + } + if (kdc) { + if (SECITEM_ItemsAreEqual(oids[i], &pkinit_kp_kdc)) { + eku |= PKINIT_EKU_PKINIT; + } + } else { + if (SECITEM_ItemsAreEqual(oids[i], &pkinit_kp_client)) { + eku |= PKINIT_EKU_PKINIT; + } + } + if (SECITEM_ItemsAreEqual(oids[i], &pkinit_kp_mssclogin)) { + eku |= PKINIT_EKU_MSSCLOGIN; + } + } + PORT_FreeArena(pool, PR_TRUE); + return eku; +} krb5_error_code crypto_cert_get_matching_data(krb5_context context, pkinit_cert_handle cert_handle, pkinit_cert_matching_data **ret_data) { - return ENOSYS; + struct _pkinit_cert_info *cert; + pkinit_cert_matching_data *md; + cert = cert_handle; + md = malloc(sizeof(*md)); + if (md == NULL) { + return ENOMEM; + } + md->ch = cert; + md->subject_dn = cert->cert->subjectName; /* FIXME: not RFC2253 */ + md->issuer_dn = cert->cert->issuerName; /* FIXME: not RFC2253 */ + md->ku_bits = cert_get_ku_bits(context, cert_handle); + md->eku_bits = cert_get_eku_bits(context, cert_handle, 0); + md->sans = NULL; /* FIXME */ + *ret_data = md; + return 0; } /* Free up "this" "self" certificate and key. */ @@ -1097,7 +1202,8 @@ krb5_error_code crypto_cert_free_matching_data(krb5_context context, pkinit_cert_matching_data *data) { - return ENOSYS; + free(data); + return 0; } /* Mark the cert tracked in the matching data structure as the one we're going -- 1.7.6.4