From 3088a82f1f5356e7a94267742cfce66fe2bbef62 Mon Sep 17 00:00:00 2001 From: Nalin Dahyabhai Date: Mon, 4 Oct 2010 22:21:51 -0400 Subject: [PATCH 043/150] - try to group the encoding templates in one area - don't need to zero-pad oakley primes - implement pkinit_process_td_trusted_certifiers() --- src/plugins/preauth/pkinit/pkinit_crypto_nss.c | 467 ++++++++++++++---------- 1 files changed, 277 insertions(+), 190 deletions(-) diff --git a/src/plugins/preauth/pkinit/pkinit_crypto_nss.c b/src/plugins/preauth/pkinit/pkinit_crypto_nss.c index c9bf929..71be9b3 100644 --- a/src/plugins/preauth/pkinit/pkinit_crypto_nss.c +++ b/src/plugins/preauth/pkinit/pkinit_crypto_nss.c @@ -48,7 +48,12 @@ #include #include +/* We should probably avoid using the default location for certificate trusts, + * unless we can be sure that the list of trusted roots isn't being shared with + * general-purpose SSL/TLS configuration, even though we're leaning on SSL/TLS + * trust settings. */ #define CONFIGDIR "/home/nalin/projects/krb5/pkinit/src/plugins/preauth/pkinit" /* FIXME */ + #define NULLCX NULL /* FIXME */ #define DEBUG_DER "derdump" @@ -84,8 +89,8 @@ struct _pkinit_plg_crypto_context { struct _pkinit_req_crypto_context { PLArenaPool *pool; - SECKEYPrivateKey *client_dh_key; /* used by clients */ - CERTCertificate *peer_cert; /* used by both clients and KDCs */ + SECKEYPrivateKey *client_dh_key; /* used by clients */ + CERTCertificate *peer_cert; /* the other party */ }; struct _pkinit_identity_crypto_context { @@ -249,6 +254,97 @@ issuer_and_serial_number_template[] = { { 0, 0, NULL, 0}, }; +struct realm { + SECItem name; +}; +struct principal_name { + SECItem name_type; + SECItem **name_string; +}; +struct kerberos_principal_name { + SECItem realm; + struct principal_name principal_name; +}; +static const SEC_ASN1Template +kerberos_string_template[] = { + { + .kind = SEC_ASN1_GENERAL_STRING, + .offset = 0, + .sub = NULL, + .size = sizeof(SECItem), + }, +}; +static const SEC_ASN1Template +realm_template[] = { + { + .kind = SEC_ASN1_GENERAL_STRING, + .offset = 0, + .sub = NULL, + .size = sizeof(SECItem), + }, +}; +static const SEC_ASN1Template +sequence_of_kerberos_string_template[] = { + { + .kind = SEC_ASN1_SEQUENCE_OF, + .offset = 0, + .sub = &kerberos_string_template, + .size = 0, + }, +}; +static const SEC_ASN1Template +principal_name_template[] = { + { + .kind = SEC_ASN1_SEQUENCE, + .offset = 0, + .sub = NULL, + .size = sizeof(struct principal_name), + }, + { + .kind = SEC_ASN1_CONTEXT_SPECIFIC | 0 | + SEC_ASN1_CONSTRUCTED | + SEC_ASN1_EXPLICIT, + .offset = offsetof(struct principal_name, name_type), + .sub = &SEC_IntegerTemplate, + .size = sizeof(SECItem), + }, + { + .kind = SEC_ASN1_CONTEXT_SPECIFIC | 1 | + SEC_ASN1_CONSTRUCTED | + SEC_ASN1_EXPLICIT, + .offset = offsetof(struct principal_name, name_string), + .sub = sequence_of_kerberos_string_template, + .size = sizeof(struct SECItem**), + }, + {0, 0, NULL, 0}, +}; +static const SEC_ASN1Template +nt_kerberos_principal_name_template[] = { + { + .kind = SEC_ASN1_SEQUENCE, + .offset = 0, + .sub = NULL, + .size = sizeof(struct kerberos_principal_name), + }, + { + .kind = SEC_ASN1_CONTEXT_SPECIFIC | 0 | + SEC_ASN1_CONSTRUCTED | + SEC_ASN1_EXPLICIT, + .offset = offsetof(struct kerberos_principal_name, realm), + .sub = &realm_template, + .size = sizeof(struct realm), + }, + { + .kind = SEC_ASN1_CONTEXT_SPECIFIC | 1 | + SEC_ASN1_CONSTRUCTED | + SEC_ASN1_EXPLICIT, + .offset = offsetof(struct kerberos_principal_name, principal_name), + .sub = &principal_name_template, + .size = sizeof(struct principal_name), + }, + {0, 0, NULL, 0}, +}; + /* OIDs. */ static unsigned char oid_pkinit_key_purpose_client_bytes[] = {0x2b, 0x06, 0x01, 0x05, 0x02, 0x03, 0x04}; @@ -280,7 +376,7 @@ static SECItem pkinit_nt_upn = { .data = oid_pkinit_name_type_upn_bytes, .len = 10, }; -static unsigned char oid_pkinit_auth_data_bytes[] = +static unsigned char oid_pkinit_auth_data_bytes[] = {0x2b, 0x06, 0x01, 0x05, 0x02, 0x03, 0x01}; static const SECOidData oid_pkinit_auth_data = { @@ -289,15 +385,15 @@ oid_pkinit_auth_data = { .len = 7, }, .offset = 0, - .desc = "PKINIT Authentication Data", + .desc = "PKINIT Client Authentication Data", .mechanism = CKM_INVALID_MECHANISM, .supportedExtension = UNSUPPORTED_CERT_EXTENSION, }; static const SECOidTag get_pkinit_data_auth_data_tag(void) { - static SECOidTag tag = 0; - if (tag == 0) { + static SECOidTag tag = SEC_OID_UNKNOWN; + if (tag == SEC_OID_UNKNOWN) { tag = SECOID_AddEntry(&oid_pkinit_auth_data); } return tag; @@ -318,8 +414,8 @@ oid_pkinit_rkey_data = { static const SECOidTag get_pkinit_data_rkey_data_tag(void) { - static SECOidTag tag = 0; - if (tag == 0) { + static SECOidTag tag = SEC_OID_UNKNOWN; + if (tag == SEC_OID_UNKNOWN) { tag = SECOID_AddEntry(&oid_pkinit_rkey_data); } return tag; @@ -337,11 +433,12 @@ oid_pkinit_dhkey_data = { .mechanism = CKM_INVALID_MECHANISM, .supportedExtension = UNSUPPORTED_CERT_EXTENSION, }; + static const SECOidTag get_pkinit_data_dhkey_data_tag(void) { - static SECOidTag tag = 0; - if (tag == 0) { + static SECOidTag tag = SEC_OID_UNKNOWN; + if (tag == SEC_OID_UNKNOWN) { tag = SECOID_AddEntry(&oid_pkinit_dhkey_data); } return tag; @@ -572,7 +669,7 @@ secitem_to_dh_pubval(SECItem *item, unsigned char **out, unsigned int *len) i = secitem_to_buf_len(&bits, out, len); PORT_FreeArena(pool, PR_TRUE); - return 0; + return i; } /* Decode a bitstring that contains an unsigned integer, and return just the @@ -598,16 +695,17 @@ secitem_from_dh_pubval(PLArenaPool *pool, static struct oakley_group { int identifier; - int bits; + int bits; /* shortest prime first, so that a sequential search will + * find the entry with the shortest suitable prime */ char name[32]; char prime[4096]; /* large enough to hold that prime */ - int generator; + long generator; /* note: oakley_parse_group() assumes that this number + * fits into a long */ char subprime[4096]; /* large enough to hold its subprime ((p-1)/2) */ } oakley_groups[] = { { 1, 768, "Oakley MODP Group 1", - "00" "FFFFFFFF FFFFFFFF C90FDAA2 2168C234 C4C6628B 80DC1CD1" "29024E08 8A67CC74 020BBEA6 3B139B22 514A0879 8E3404DD" "EF9519B3 CD3A431B 302B0A6D F25F1437 4FE1356D 6D51C245" @@ -621,7 +719,6 @@ static struct oakley_group { { 2, 1024, "Oakley MODP Group 2", - "00" "FFFFFFFF FFFFFFFF C90FDAA2 2168C234 C4C6628B 80DC1CD1" "29024E08 8A67CC74 020BBEA6 3B139B22 514A0879 8E3404DD" "EF9519B3 CD3A431B 302B0A6D F25F1437 4FE1356D 6D51C245" @@ -639,7 +736,6 @@ static struct oakley_group { { 5, 1536, "Oakley MODP Group 5", - "00" "FFFFFFFF FFFFFFFF C90FDAA2 2168C234 C4C6628B 80DC1CD1" "29024E08 8A67CC74 020BBEA6 3B139B22 514A0879 8E3404DD" "EF9519B3 CD3A431B 302B0A6D F25F1437 4FE1356D 6D51C245" @@ -661,7 +757,6 @@ static struct oakley_group { { 14, 2048, "Oakley MODP Group 14", - "00" "FFFFFFFF FFFFFFFF C90FDAA2 2168C234 C4C6628B 80DC1CD1" "29024E08 8A67CC74 020BBEA6 3B139B22 514A0879 8E3404DD" "EF9519B3 CD3A431B 302B0A6D F25F1437 4FE1356D 6D51C245" @@ -689,7 +784,6 @@ static struct oakley_group { { 15, 3072, "Oakley MODP Group 15", - "00" "FFFFFFFF FFFFFFFF C90FDAA2 2168C234 C4C6628B 80DC1CD1" "29024E08 8A67CC74 020BBEA6 3B139B22 514A0879 8E3404DD" "EF9519B3 CD3A431B 302B0A6D F25F1437 4FE1356D 6D51C245" @@ -727,7 +821,6 @@ static struct oakley_group { { 16, 4096, "Oakley MODP Group 16", - "00" "FFFFFFFF FFFFFFFF C90FDAA2 2168C234 C4C6628B 80DC1CD1" "29024E08 8A67CC74 020BBEA6 3B139B22 514A0879 8E3404DD" "EF9519B3 CD3A431B 302B0A6D F25F1437 4FE1356D 6D51C245" @@ -776,6 +869,7 @@ static struct oakley_group { } }; +/* Convert a string of hexadecimal characters to a binary integer. */ static SECItem * hex_to_secitem(const char *hex, SECItem *item) { @@ -785,6 +879,8 @@ hex_to_secitem(const char *hex, SECItem *item) j = 0; c = hex[0]; + /* If the high bit would be set, prepend a zero byte to keep the result + * from being negative. */ if ((c == '8') || (c == '9') || ((c >= 'a') && (c <= 'f')) || @@ -855,7 +951,7 @@ oakley_parse_group(PLArenaPool *pool, struct oakley_group *group, return ENOMEM; } params->p = *t; - /* FIXME: this assumes that the generator fits in a long. */ + /* Encode the generator. */ if (SEC_ASN1EncodeInteger(pool, ¶ms->g, group->generator) != ¶ms->g) { return ENOMEM; @@ -1066,6 +1162,27 @@ client_process_dh(krb5_context context, return 0; } +/* Given a binary-encoded integer, count the number of bits. */ +static int +get_integer_bits(SECItem *integer) +{ + unsigned int i; + unsigned char c; + int size = 0; + for (i = 0; i < integer->len; i++) { + c = integer->data[i]; + if (c != 0) { + size = integer->len - i - 1; + while (c != 0) { + c >>= 1; + size++; + } + break; + } + } + return size; +} + /* Verify that the client-supplied parameters include a prime of sufficient * size. */ krb5_error_code @@ -1093,7 +1210,7 @@ server_check_dh(krb5_context context, return ENOMEM; } - if (params->p.len * 8 < (unsigned int) minbits) { + if (get_integer_bits(¶ms->p) < minbits) { PORT_FreeArena(pool, PR_TRUE); return KRB5KDC_ERR_DH_KEY_PARAMETERS_NOT_ACCEPTED; } @@ -1247,6 +1364,8 @@ server_process_dh(krb5_context context, return 0; } +/* Create the issuer-and-serial portion of an external principal identifier for + * a KDC's cert that we already have. */ krb5_error_code create_issuerAndSerial(krb5_context context, pkinit_plg_crypto_context plg_cryptoctx, @@ -1259,19 +1378,20 @@ create_issuerAndSerial(krb5_context context, struct issuer_and_serial_number isn; SECItem item; - /* Check if we have selected an identity cert. */ - if (id_cryptoctx->id_cert == NULL) { - return ENOENT; + /* Check if we have a peer cert. If we don't have one, that's okay. */ + if (req_cryptoctx->peer_cert == NULL) { + return 0; } + /* Scratch arena. */ pool = PORT_NewArena(sizeof(double)); if (pool == NULL) { return ENOMEM; } - /* Encode the issuer/serial. */ - isn.issuer = id_cryptoctx->id_cert->derIssuer; - isn.serial = id_cryptoctx->id_cert->serialNumber; + /* Encode the peer's issuer/serial. */ + isn.issuer = req_cryptoctx->peer_cert->derIssuer; + isn.serial = req_cryptoctx->peer_cert->serialNumber; memset(&item, 0, sizeof(item)); if (SEC_ASN1EncodeItem(id_cryptoctx->id_cert->arena, &item, &isn, issuer_and_serial_number_template) != &item) { @@ -1314,6 +1434,7 @@ create_krb5_supportedCMSTypes(krb5_context context, SEC_OID_AES_128_KEY_WRAP, /* no parameters */ SEC_OID_AES_192_KEY_WRAP, /* no parameters */ SEC_OID_AES_256_KEY_WRAP, /* no parameters */ + /* RC2 key wrap requires parameters */ }; krb5_algorithm_identifier **ids, *id; unsigned int i; @@ -1409,14 +1530,16 @@ create_krb5_trustedCertifiers(krb5_context context, } memset(id, 0, sizeof(*id)); /* Use the certificate's subject key ID iff it's - * actually in the certificate. */ + * actually in the certificate. Allocate the memory + * from the heap because it'll be freed by other parts + * of the pkinit module. */ if ((node->cert->keyIDGenerated ? secitem_to_buf_len(&node->cert->derSubject, - &id->subjectName.data, - &id->subjectName.length) : + &id->subjectName.data, + &id->subjectName.length) : secitem_to_buf_len(&node->cert->subjectKeyID, - &id->subjectKeyIdentifier.data, - &id->subjectKeyIdentifier.length)) != 0) { + &id->subjectKeyIdentifier.data, + &id->subjectKeyIdentifier.length)) != 0) { /* Free the earlier items. */ free(ids[i]); free_n_principal_identifiers(ids, i - 1); @@ -1473,7 +1596,8 @@ crypto_free_cert_info(krb5_context context, return 0; /* FIXME: should we nuke some lists here? */ } -/* Count how many candidate "self" certificates and keys we have. */ +/* Count how many candidate "self" certificates and keys we have. We could as + * easily count the keys. */ krb5_error_code crypto_cert_get_count(krb5_context context, pkinit_plg_crypto_context plg_cryptoctx, @@ -1569,6 +1693,68 @@ crypto_cert_iteration_next(krb5_context context, return 0; } +static int +cert_load_certs_with_keys_from_slot(pkinit_identity_crypto_context id, + PK11SlotInfo *slot) +{ + CERTCertificate *cert; + CERTCertList *clist; + CERTCertListNode *cnode; + SECKEYPrivateKey *key; + int status; + /* Get the list of certs, and skip the slot if it doesn't have + * any. */ + clist = PK11_ListCertsInSlot(slot); + if (clist == NULL) { + pkiDebug("%s: nothing found in token \"%s\"\n", + __FUNCTION__, PK11_GetTokenName(slot)); + return 0; + } + if (CERT_LIST_EMPTY(clist)) { + CERT_DestroyCertList(clist); + pkiDebug("%s: nothing found in token \"%s\"\n", + __FUNCTION__, PK11_GetTokenName(slot)); + return 0; + } + /* Walk the list of certs, and for each one for which we can + * find the matching private key, add it and the keys to the + * lists. */ + for (cnode = CERT_LIST_HEAD(clist); + (cnode != NULL) && + (cnode->cert != NULL) && + !CERT_LIST_END(cnode, clist); + cnode = CERT_LIST_NEXT(cnode)) { + pkiDebug("%s: checking for key for \"%s\"\n", + __FUNCTION__, + cnode->cert->nickname ? + cnode->cert->nickname : "(no name)"); + key = PK11_FindPrivateKeyFromCert(slot, cnode->cert, NULLCX); + if (key == NULL) { + pkiDebug("%s: no key for \"%s\"\n", + __FUNCTION__, + cnode->cert->nickname ? + cnode->cert->nickname : "(no name)"); + continue; + } + pkiDebug("%s: using \"%s\" and its matching key\n", + __FUNCTION__, + cnode->cert->nickname ? + cnode->cert->nickname : "(no name)"); + /* DestroyCertList frees all of the certs in the list, + * so we need to create a copy that it can own. */ + cert = CERT_DupCertificate(cnode->cert); + if (CERT_AddCertToListTail(id->id_certs, cert) != SECSuccess) { + status = ENOMEM; + } + if (SECKEY_AddPrivateKeyToListTail(id->id_keys, + key) != SECSuccess) { + status = ENOMEM; + } + } + CERT_DestroyCertList(clist); + return status; +} + /* Load all of the certificates in all of the tokens for which we also have * matching secret keys. */ static int @@ -1576,10 +1762,6 @@ cert_load_default_identity(pkinit_identity_crypto_context id) { PK11SlotList *slist; PK11SlotListElement *sle; - SECKEYPrivateKey *key; - CERTCertList *clist; - CERTCertListNode *cnode; - CERTCertificate *cert; int status; /* Get the list of tokens. All of them. */ @@ -1601,57 +1783,28 @@ cert_load_default_identity(pkinit_identity_crypto_context id) } /* Get the list of certs, and skip the slot if it doesn't have * any. */ - clist = PK11_ListCertsInSlot(sle->slot); - if (clist == NULL) { - pkiDebug("%s: nothing found in token \"%s\"\n", - __FUNCTION__, PK11_GetTokenName(sle->slot)); - continue; + status = cert_load_certs_with_keys_from_slot(id, sle->slot); + if (status != 0) { + PK11_FreeSlotList(slist); + return status; } - if (CERT_LIST_EMPTY(clist)) { - CERT_DestroyCertList(clist); - pkiDebug("%s: nothing found in token \"%s\"\n", + } + /* Now try logging in to the slots that still require it. */ + for (sle = slist->head; sle != NULL; sle = sle->next) { + /* Skip over slots we've already used. */ + if (PK11_IsLoggedIn(sle->slot, NULLCX) || + !PK11_NeedLogin(sle->slot)) { + pkiDebug("%s: skipping token \"%s\"\n", __FUNCTION__, PK11_GetTokenName(sle->slot)); continue; } - /* Walk the list of certs, and for each one for which we can - * find the matching private key, add it and the keys to the - * lists. */ - for (cnode = CERT_LIST_HEAD(clist); - (cnode != NULL) && - (cnode->cert != NULL) && - !CERT_LIST_END(cnode, clist); - cnode = CERT_LIST_NEXT(cnode)) { - pkiDebug("%s: checking for key for \"%s\"\n", - __FUNCTION__, - cnode->cert->nickname ? - cnode->cert->nickname : "(no name)"); - key = PK11_FindPrivateKeyFromCert(sle->slot, - cnode->cert, - NULLCX); - if (key == NULL) { - pkiDebug("%s: no key for \"%s\"\n", - __FUNCTION__, - cnode->cert->nickname ? - cnode->cert->nickname : "(no name)"); - continue; - } - pkiDebug("%s: using \"%s\" and its matching key\n", - __FUNCTION__, - cnode->cert->nickname ? - cnode->cert->nickname : "(no name)"); - /* DestroyCertList frees all of the certs in the list, - * so we need to create a copy that it can own. */ - cert = CERT_DupCertificate(cnode->cert); - if (CERT_AddCertToListTail(id->id_certs, - cert) != SECSuccess) { - status = ENOMEM; - } - if (SECKEY_AddPrivateKeyToListTail(id->id_keys, - key) != SECSuccess) { - status = ENOMEM; - } + /* Get the list of certs, and skip the slot if it doesn't have + * any. */ + status = cert_load_certs_with_keys_from_slot(id, sle->slot); + if (status != 0) { + PK11_FreeSlotList(slist); + return status; } - CERT_DestroyCertList(clist); } PK11_FreeSlotList(slist); return status; @@ -1674,6 +1827,7 @@ cert_get_ext_by_tag(CERTCertificate *cert, SECOidTag tag) } return NULL; } + static unsigned int cert_get_ku_bits(krb5_context context, CERTCertificate *cert) { @@ -1739,6 +1893,7 @@ cert_get_eku_bits(krb5_context context, CERTCertificate *cert, int kdc) PORT_FreeArena(pool, PR_TRUE); return eku; } + krb5_error_code crypto_cert_get_matching_data(krb5_context context, pkinit_cert_handle cert_handle, @@ -1751,7 +1906,7 @@ crypto_cert_get_matching_data(krb5_context context, } md->ch = cert_handle; md->subject_dn = strdup(cert_handle->cert->subjectName); - /* FIXME: not RFC2253 */ + /* FIXME: these not RFC2253 */ md->issuer_dn = strdup(cert_handle->cert->issuerName); /* FIXME: not RFC2253 */ md->ku_bits = cert_get_ku_bits(context, cert_handle->cert); @@ -1840,6 +1995,40 @@ crypto_load_cas_and_crls(krb5_context context, int idtype, int catype, char *id) { return 0; /* FIXME */ + switch (idtype) { + case IDTYPE_FILE: + return ENOSYS; + break; + case IDTYPE_DIR: + return ENOSYS; + break; + case IDTYPE_PKCS11: + return ENOSYS; + break; + case IDTYPE_ENVVAR: + return ENOSYS; + break; + case IDTYPE_PKCS12: + return ENOSYS; + break; + default: + return ENOSYS; + break; + } + switch (catype) { + case CATYPE_ANCHORS: + return ENOSYS; + break; + case CATYPE_INTERMEDIATES: + return ENOSYS; + break; + case CATYPE_CRLS: + return ENOSYS; + break; + default: + return ENOSYS; + break; + } } /* Retrieve the client's copy of the KDC's certificate. */ @@ -1966,8 +2155,6 @@ pkinit_process_td_dh_params(krb5_context context, struct domain_parameters params; SECItem item; int i, size; - unsigned int j; - unsigned char c; /* Initial guess is a hard-coded lower bound. */ *new_dh_size = 512; for (i = 0; (algId != NULL) && (algId[i] != NULL); i++) { @@ -1981,18 +2168,7 @@ pkinit_process_td_dh_params(krb5_context context, } /* Count the size of the prime by finding the first non-zero * byte and working out the size of the integer. */ - size = 0; - for (j = 0; j < params.p.len; j++) { - c = params.p.data[j]; - if (c != 0) { - size = params.p.len - j - 1; - while (c != 0) { - c >>= 1; - size++; - } - break; - } - } + size = get_integer_bits(¶ms.p); if (size > *new_dh_size) { *new_dh_size = size; } @@ -2217,7 +2393,9 @@ pkinit_process_td_trusted_certifiers(krb5_context context, krb5_external_principal_identifier **trustedCertifiers, int td_type) { - return ENOSYS; + /* We should select a different client certificate based on the list of + * trusted certifiers, but for now we'll just chicken out. */ + return KRB5KDC_ERR_PREAUTH_FAILED; } /* Check if the encoded issuer/serial matches our (the KDC's) certificate. */ @@ -2435,97 +2613,6 @@ cert_add_upn(PLArenaPool *pool, krb5_context context, return i; } -struct realm { - SECItem name; -}; -struct principal_name { - SECItem name_type; - SECItem **name_string; -}; -struct kerberos_principal_name { - SECItem realm; - struct principal_name principal_name; -}; -static const SEC_ASN1Template -kerberos_string_template[] = { - { - .kind = SEC_ASN1_GENERAL_STRING, - .offset = 0, - .sub = NULL, - .size = sizeof(SECItem), - }, -}; -static const SEC_ASN1Template -realm_template[] = { - { - .kind = SEC_ASN1_GENERAL_STRING, - .offset = 0, - .sub = NULL, - .size = sizeof(SECItem), - }, -}; -static const SEC_ASN1Template -sequence_of_kerberos_string_template[] = { - { - .kind = SEC_ASN1_SEQUENCE_OF, - .offset = 0, - .sub = &kerberos_string_template, - .size = 0, - }, -}; -static const SEC_ASN1Template -principal_name_template[] = { - { - .kind = SEC_ASN1_SEQUENCE, - .offset = 0, - .sub = NULL, - .size = sizeof(struct principal_name), - }, - { - .kind = SEC_ASN1_CONTEXT_SPECIFIC | 0 | - SEC_ASN1_CONSTRUCTED | - SEC_ASN1_EXPLICIT, - .offset = offsetof(struct principal_name, name_type), - .sub = &SEC_IntegerTemplate, - .size = sizeof(SECItem), - }, - { - .kind = SEC_ASN1_CONTEXT_SPECIFIC | 1 | - SEC_ASN1_CONSTRUCTED | - SEC_ASN1_EXPLICIT, - .offset = offsetof(struct principal_name, name_string), - .sub = sequence_of_kerberos_string_template, - .size = sizeof(struct SECItem**), - }, - {0, 0, NULL, 0}, -}; -static const SEC_ASN1Template -nt_kerberos_principal_name_template[] = { - { - .kind = SEC_ASN1_SEQUENCE, - .offset = 0, - .sub = NULL, - .size = sizeof(struct kerberos_principal_name), - }, - { - .kind = SEC_ASN1_CONTEXT_SPECIFIC | 0 | - SEC_ASN1_CONSTRUCTED | - SEC_ASN1_EXPLICIT, - .offset = offsetof(struct kerberos_principal_name, realm), - .sub = &realm_template, - .size = sizeof(struct realm), - }, - { - .kind = SEC_ASN1_CONTEXT_SPECIFIC | 1 | - SEC_ASN1_CONSTRUCTED | - SEC_ASN1_EXPLICIT, - .offset = offsetof(struct kerberos_principal_name, principal_name), - .sub = &principal_name_template, - .size = sizeof(struct principal_name), - }, - {0, 0, NULL, 0}, -}; - static int cert_add_kpn(PLArenaPool *pool, krb5_context context, krb5_principal **sans, int *n_sans, SECItem *name) -- 1.7.6.4