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 check_pkinit_san(hx509_validate_ctx ctx, heim_any *a) { KRB5PrincipalName kn; unsigned i; size_t size; int ret; ret = decode_KRB5PrincipalName(a->data, a->length, &kn, &size); if (ret) { validate_print(ctx, HX509_VALIDATE_F_VALIDATE, "Decoding kerberos name in SAN failed: %d", ret); return 1; } if (size != a->length) { validate_print(ctx, HX509_VALIDATE_F_VALIDATE, "Decoding kerberos name have extra bits on the end"); return 1; } /* print kerberos principal, add code to quote / within components */ for (i = 0; i < kn.principalName.name_string.len; i++) { validate_print(ctx, HX509_VALIDATE_F_VERBOSE, "%s", kn.principalName.name_string.val[i]); if (i + 1 < kn.principalName.name_string.len) validate_print(ctx, HX509_VALIDATE_F_VERBOSE, "/"); } validate_print(ctx, HX509_VALIDATE_F_VERBOSE, "@"); validate_print(ctx, HX509_VALIDATE_F_VERBOSE, "%s", kn.realm); free_KRB5PrincipalName(&kn); return 0; }
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; }