static int match_rfc_san(krb5_context context, krb5_kdc_configuration *config, hx509_context hx509ctx, hx509_cert client_cert, krb5_const_principal match) { hx509_octet_string_list list; int ret, found = 0; size_t i; memset(&list, 0 , sizeof(list)); ret = hx509_cert_find_subjectAltName_otherName(hx509ctx, client_cert, &asn1_oid_id_pkinit_san, &list); if (ret) goto out; for (i = 0; !found && i < list.len; i++) { krb5_principal_data principal; KRB5PrincipalName kn; size_t size; ret = decode_KRB5PrincipalName(list.val[i].data, list.val[i].length, &kn, &size); if (ret) { const char *msg = krb5_get_error_message(context, ret); kdc_log(context, config, 0, "Decoding kerberos name in certificate failed: %s", msg); krb5_free_error_message(context, msg); break; } if (size != list.val[i].length) { kdc_log(context, config, 0, "Decoding kerberos name have extra bits on the end"); return KRB5_KDC_ERR_CLIENT_NAME_MISMATCH; } memset(&principal, 0, sizeof (principal)); principal.name = kn.principalName; principal.realm = kn.realm; if (krb5_principal_compare(context, &principal, match) == TRUE) found = 1; free_KRB5PrincipalName(&kn); } out: hx509_free_octet_string_list(&list); if (ret) return ret; if (!found) return KRB5_KDC_ERR_CLIENT_NAME_MISMATCH; return 0; }
static int match_ms_upn_san(krb5_context context, krb5_kdc_configuration *config, hx509_context hx509ctx, hx509_cert client_cert, HDB *clientdb, hdb_entry_ex *client) { hx509_octet_string_list list; krb5_principal principal = NULL; int ret; MS_UPN_SAN upn; size_t size; memset(&list, 0 , sizeof(list)); ret = hx509_cert_find_subjectAltName_otherName(hx509ctx, client_cert, &asn1_oid_id_pkinit_ms_san, &list); if (ret) goto out; if (list.len != 1) { kdc_log(context, config, 0, "More then one PK-INIT MS UPN SAN"); ret = KRB5_KDC_ERR_CLIENT_NAME_MISMATCH; goto out; } ret = decode_MS_UPN_SAN(list.val[0].data, list.val[0].length, &upn, &size); if (ret) { kdc_log(context, config, 0, "Decode of MS-UPN-SAN failed"); goto out; } if (size != list.val[0].length) { free_MS_UPN_SAN(&upn); kdc_log(context, config, 0, "Trailing data in "); ret = KRB5_KDC_ERR_CLIENT_NAME_MISMATCH; goto out; } kdc_log(context, config, 0, "found MS UPN SAN: %s", upn); ret = krb5_parse_name(context, upn, &principal); free_MS_UPN_SAN(&upn); if (ret) { kdc_log(context, config, 0, "Failed to parse principal in MS UPN SAN"); goto out; } if (clientdb->hdb_check_pkinit_ms_upn_match) { ret = clientdb->hdb_check_pkinit_ms_upn_match(context, clientdb, client, principal); } else { /* * This is very wrong, but will do for a fallback */ strupr(principal->realm); if (krb5_principal_compare(context, principal, client->entry.principal) == FALSE) ret = KRB5_KDC_ERR_CLIENT_NAME_MISMATCH; } out: if (principal) krb5_free_principal(context, principal); hx509_free_octet_string_list(&list); return ret; }
krb5_error_code _gsspku2u_principal(krb5_context context, struct hx509_cert_data *cert, krb5_principal *principal) { hx509_octet_string_list list; krb5_error_code ret; int found = 0; unsigned i; char *name; *principal = NULL; /* * First try to map PKINIT SAN to a Kerberos principal */ ret = hx509_cert_find_subjectAltName_otherName(context->hx509ctx, cert, &asn1_oid_id_pkinit_san, &list); if (ret == 0) { for (i = 0; !found && i < list.len; i++) { KRB5PrincipalName r; ret = decode_KRB5PrincipalName(list.val[i].data, list.val[i].length, &r, NULL); if (ret) continue; ret = _krb5_principalname2krb5_principal(context, principal, r.principalName, KRB5_PKU2U_REALM_NAME); free_KRB5PrincipalName(&r); if (ret == 0) found = 1; } hx509_free_octet_string_list(&list); } if (found) return 0; /* * */ ret = hx509_cert_get_appleid(context->hx509ctx, cert, &name); if (ret == 0) { ret = krb5_make_principal(context, principal, KRB5_PKU2U_REALM_NAME, name, NULL); hx509_xfree(name); if (ret == 0) { (*principal)->name.name_type = KRB5_NT_ENTERPRISE_PRINCIPAL; return 0; } } /* * Give up and just WELLKNOWN and assertion instead */ ret = krb5_make_principal(context, principal, KRB5_PKU2U_REALM_NAME, KRB5_WELLKNOWN_NAME, KRB5_NULL_NAME, NULL); if (ret == 0) (*principal)->name.name_type = KRB5_NT_WELLKNOWN; return ret; }
static int match_ms_upn_san(krb5_context context, krb5_kdc_configuration *config, hx509_context hx509ctx, hx509_cert client_cert, krb5_const_principal match) { hx509_octet_string_list list; krb5_principal principal = NULL; int ret, found = 0; MS_UPN_SAN upn; size_t size; memset(&list, 0 , sizeof(list)); ret = hx509_cert_find_subjectAltName_otherName(hx509ctx, client_cert, oid_id_pkinit_ms_san(), &list); if (ret) goto out; if (list.len != 1) { kdc_log(context, config, 0, "More then one PK-INIT MS UPN SAN"); goto out; } ret = decode_MS_UPN_SAN(list.val[0].data, list.val[0].length, &upn, &size); if (ret) { kdc_log(context, config, 0, "Decode of MS-UPN-SAN failed"); goto out; } kdc_log(context, config, 0, "found MS UPN SAN: %s", upn); ret = krb5_parse_name(context, upn, &principal); free_MS_UPN_SAN(&upn); if (ret) { kdc_log(context, config, 0, "Failed to parse principal in MS UPN SAN"); goto out; } /* * This is very wrong, but will do for now, should really and a * plugin to the windc layer to very this ACL. */ strupr(principal->realm); if (krb5_principal_compare(context, principal, match) == TRUE) found = 1; out: if (principal) krb5_free_principal(context, principal); hx509_free_octet_string_list(&list); if (ret) return ret; if (!found) return KRB5_KDC_ERR_CLIENT_NAME_MISMATCH; return 0; }