static int test_expand(hx509_context context, const char *name, const char *expected) { hx509_env env = NULL; hx509_name n; char *s; int ret; hx509_env_add(context, &env, "uid", "lha"); ret = hx509_parse_name(context, name, &n); if (ret) return 1; ret = hx509_name_expand(context, n, env); hx509_env_free(&env); if (ret) return 1; ret = hx509_name_to_string(n, &s); hx509_name_free(&n); if (ret) return 1; ret = strcmp(s, expected) != 0; free(s); if (ret) return 1; return 0; }
int hx509_ci_print_names(hx509_context context, void *ctx, hx509_cert c) { Certificate *cert; hx509_name n; char *s, *i; cert = _hx509_get_cert(c); _hx509_name_from_Name(&cert->tbsCertificate.subject, &n); hx509_name_to_string(n, &s); hx509_name_free(&n); _hx509_name_from_Name(&cert->tbsCertificate.issuer, &n); hx509_name_to_string(n, &i); hx509_name_free(&n); fprintf(ctx, "subject: %s\nissuer: %s\n", s, i); free(s); free(i); return 0; }
int _hx509_unparse_Name(const Name *aname, char **str) { hx509_name name; int ret; ret = _hx509_name_from_Name(aname, &name); if (ret) return ret; ret = hx509_name_to_string(name, str); hx509_name_free(&name); return ret; }
int _hx509_request_print(hx509_context context, hx509_request req, FILE *f) { int ret; if (req->name) { char *subject; ret = hx509_name_to_string(req->name, &subject); if (ret) { hx509_set_error_string(context, 0, ret, "Failed to print name"); return ret; } fprintf(f, "name: %s\n", subject); free(subject); } return 0; }
static int test_name(hx509_context context, const char *name) { hx509_name n; char *s; int ret; ret = hx509_parse_name(context, name, &n); if (ret) return 1; ret = hx509_name_to_string(n, &s); if (ret) return 1; if (strcmp(s, name) != 0) return 1; hx509_name_free(&n); free(s); return 0; }
krb5_error_code krb5_kdc_pk_initialize(krb5_context context, krb5_kdc_configuration *config, const char *user_id, const char *anchors, char **pool, char **revoke_list) { const char *file; char *fn = NULL; krb5_error_code ret; file = krb5_config_get_string(context, NULL, "libdefaults", "moduli", NULL); ret = _krb5_parse_moduli(context, file, &moduli); if (ret) krb5_err(context, 1, ret, "PKINIT: failed to load modidi file"); principal_mappings.len = 0; principal_mappings.val = NULL; ret = _krb5_pk_load_id(context, &kdc_identity, user_id, anchors, pool, revoke_list, NULL, NULL, NULL); if (ret) { krb5_warn(context, ret, "PKINIT: "); config->enable_pkinit = 0; return ret; } { hx509_query *q; hx509_cert cert; ret = hx509_query_alloc(context->hx509ctx, &q); if (ret) { krb5_warnx(context, "PKINIT: out of memory"); return ENOMEM; } hx509_query_match_option(q, HX509_QUERY_OPTION_PRIVATE_KEY); if (config->pkinit_kdc_friendly_name) hx509_query_match_friendly_name(q, config->pkinit_kdc_friendly_name); ret = hx509_certs_find(context->hx509ctx, kdc_identity->certs, q, &cert); hx509_query_free(context->hx509ctx, q); if (ret == 0) { if (hx509_cert_check_eku(context->hx509ctx, cert, &asn1_oid_id_pkkdcekuoid, 0)) { hx509_name name; char *str; ret = hx509_cert_get_subject(cert, &name); if (ret == 0) { hx509_name_to_string(name, &str); krb5_warnx(context, "WARNING Found KDC certificate (%s)" "is missing the PK-INIT KDC EKU, this is bad for " "interoperability.", str); hx509_name_free(&name); free(str); } } hx509_cert_free(cert); } else krb5_warnx(context, "PKINIT: failed to find a signing " "certifiate with a public key"); } if (krb5_config_get_bool_default(context, NULL, FALSE, "kdc", "pkinit_allow_proxy_certificate", NULL)) config->pkinit_allow_proxy_certs = 1; file = krb5_config_get_string(context, NULL, "kdc", "pkinit_mappings_file", NULL); if (file == NULL) { int aret; aret = asprintf(&fn, "%s/pki-mapping", hdb_db_dir(context)); if (aret == -1) { krb5_warnx(context, "PKINIT: out of memory"); return ENOMEM; } file = fn; } load_mappings(context, file); if (fn) free(fn); return 0; }
krb5_error_code _kdc_pk_check_client(krb5_context context, krb5_kdc_configuration *config, HDB *clientdb, hdb_entry_ex *client, pk_client_params *cp, char **subject_name) { const HDB_Ext_PKINIT_acl *acl; const HDB_Ext_PKINIT_cert *pc; krb5_error_code ret; hx509_name name; size_t i; if (cp->cert == NULL) { *subject_name = strdup("anonymous client client"); if (*subject_name == NULL) return ENOMEM; return 0; } ret = hx509_cert_get_base_subject(context->hx509ctx, cp->cert, &name); if (ret) return ret; ret = hx509_name_to_string(name, subject_name); hx509_name_free(&name); if (ret) return ret; kdc_log(context, config, 0, "Trying to authorize PK-INIT subject DN %s", *subject_name); ret = hdb_entry_get_pkinit_cert(&client->entry, &pc); if (ret == 0 && pc) { hx509_cert cert; size_t j; for (j = 0; j < pc->len; j++) { cert = hx509_cert_init_data(context->hx509ctx, pc->val[j].cert.data, pc->val[j].cert.length, NULL); if (cert == NULL) continue; ret = hx509_cert_cmp(cert, cp->cert); hx509_cert_free(cert); if (ret == 0) { kdc_log(context, config, 5, "Found matching PK-INIT cert in hdb"); return 0; } } } if (config->pkinit_princ_in_cert) { ret = match_rfc_san(context, config, context->hx509ctx, cp->cert, client->entry.principal); if (ret == 0) { kdc_log(context, config, 5, "Found matching PK-INIT SAN in certificate"); return 0; } ret = match_ms_upn_san(context, config, context->hx509ctx, cp->cert, clientdb, client); if (ret == 0) { kdc_log(context, config, 5, "Found matching MS UPN SAN in certificate"); return 0; } } ret = hdb_entry_get_pkinit_acl(&client->entry, &acl); if (ret == 0 && acl != NULL) { /* * Cheat here and compare the generated name with the string * and not the reverse. */ for (i = 0; i < acl->len; i++) { if (strcmp(*subject_name, acl->val[0].subject) != 0) continue; /* Don't support isser and anchor checking right now */ if (acl->val[0].issuer) continue; if (acl->val[0].anchor) continue; kdc_log(context, config, 5, "Found matching PK-INIT database ACL"); return 0; } } for (i = 0; i < principal_mappings.len; i++) { krb5_boolean b; b = krb5_principal_compare(context, client->entry.principal, principal_mappings.val[i].principal); if (b == FALSE) continue; if (strcmp(principal_mappings.val[i].subject, *subject_name) != 0) continue; kdc_log(context, config, 5, "Found matching PK-INIT FILE ACL"); return 0; } ret = KRB5_KDC_ERR_CLIENT_NAME_MISMATCH; krb5_set_error_message(context, ret, "PKINIT no matching principals for %s", *subject_name); kdc_log(context, config, 5, "PKINIT no matching principals for %s", *subject_name); free(*subject_name); *subject_name = NULL; return ret; }
int hx509_validate_cert(hx509_context context, hx509_validate_ctx ctx, hx509_cert cert) { Certificate *c = _hx509_get_cert(cert); TBSCertificate *t = &c->tbsCertificate; hx509_name issuer, subject; char *str; struct cert_status status; int ret; memset(&status, 0, sizeof(status)); if (_hx509_cert_get_version(c) != 3) validate_print(ctx, HX509_VALIDATE_F_VERBOSE, "Not version 3 certificate\n"); if ((t->version == NULL || *t->version < 2) && t->extensions) validate_print(ctx, HX509_VALIDATE_F_VALIDATE, "Not version 3 certificate with extensions\n"); if (_hx509_cert_get_version(c) >= 3 && t->extensions == NULL) validate_print(ctx, HX509_VALIDATE_F_VALIDATE, "Version 3 certificate without extensions\n"); ret = hx509_cert_get_subject(cert, &subject); if (ret) abort(); hx509_name_to_string(subject, &str); validate_print(ctx, HX509_VALIDATE_F_VERBOSE, "subject name: %s\n", str); free(str); ret = hx509_cert_get_issuer(cert, &issuer); if (ret) abort(); hx509_name_to_string(issuer, &str); validate_print(ctx, HX509_VALIDATE_F_VERBOSE, "issuer name: %s\n", str); free(str); if (hx509_name_cmp(subject, issuer) == 0) { status.selfsigned = 1; validate_print(ctx, HX509_VALIDATE_F_VERBOSE, "\tis a self-signed certificate\n"); } validate_print(ctx, HX509_VALIDATE_F_VERBOSE, "Validity:\n"); Time2string(&t->validity.notBefore, &str); validate_print(ctx, HX509_VALIDATE_F_VERBOSE, "\tnotBefore %s\n", str); free(str); Time2string(&t->validity.notAfter, &str); validate_print(ctx, HX509_VALIDATE_F_VERBOSE, "\tnotAfter %s\n", str); free(str); if (t->extensions) { int i, j; if (t->extensions->len == 0) { validate_print(ctx, HX509_VALIDATE_F_VALIDATE|HX509_VALIDATE_F_VERBOSE, "The empty extensions list is not " "allowed by PKIX\n"); } for (i = 0; i < t->extensions->len; i++) { for (j = 0; check_extension[j].name; j++) if (der_heim_oid_cmp(check_extension[j].oid, &t->extensions->val[i].extnID) == 0) break; if (check_extension[j].name == NULL) { int flags = HX509_VALIDATE_F_VERBOSE; if (t->extensions->val[i].critical) flags |= HX509_VALIDATE_F_VALIDATE; validate_print(ctx, flags, "don't know what "); if (t->extensions->val[i].critical) validate_print(ctx, flags, "and is CRITICAL "); if (ctx->flags & flags) hx509_oid_print(&t->extensions->val[i].extnID, validate_vprint, ctx); validate_print(ctx, flags, " is\n"); continue; } validate_print(ctx, HX509_VALIDATE_F_VALIDATE|HX509_VALIDATE_F_VERBOSE, "checking extention: %s\n", check_extension[j].name); (*check_extension[j].func)(ctx, &status, check_extension[j].cf, &t->extensions->val[i]); } } else validate_print(ctx, HX509_VALIDATE_F_VERBOSE, "no extentions\n"); if (status.isca) { if (!status.haveSKI) validate_print(ctx, HX509_VALIDATE_F_VALIDATE, "CA certificate have no SubjectKeyIdentifier\n"); } else { if (!status.haveAKI) validate_print(ctx, HX509_VALIDATE_F_VALIDATE, "Is not CA and doesn't have " "AuthorityKeyIdentifier\n"); } if (!status.haveSKI) validate_print(ctx, HX509_VALIDATE_F_VALIDATE, "Doesn't have SubjectKeyIdentifier\n"); if (status.isproxy && status.isca) validate_print(ctx, HX509_VALIDATE_F_VALIDATE, "Proxy and CA at the same time!\n"); if (status.isproxy) { if (status.haveSAN) validate_print(ctx, HX509_VALIDATE_F_VALIDATE, "Proxy and have SAN\n"); if (status.haveIAN) validate_print(ctx, HX509_VALIDATE_F_VALIDATE, "Proxy and have IAN\n"); } if (hx509_name_is_null_p(subject) && !status.haveSAN) validate_print(ctx, HX509_VALIDATE_F_VALIDATE, "NULL subject DN and doesn't have a SAN\n"); if (!status.selfsigned && !status.haveCRLDP) validate_print(ctx, HX509_VALIDATE_F_VALIDATE, "Not a CA nor PROXY and doesn't have" "CRL Dist Point\n"); if (status.selfsigned) { ret = _hx509_verify_signature_bitstring(context, cert, &c->signatureAlgorithm, &c->tbsCertificate._save, &c->signatureValue); if (ret == 0) validate_print(ctx, HX509_VALIDATE_F_VERBOSE, "Self-signed certificate was self-signed\n"); else validate_print(ctx, HX509_VALIDATE_F_VALIDATE, "Self-signed certificate NOT really self-signed!\n"); } hx509_name_free(&subject); hx509_name_free(&issuer); return 0; }
int hx509_ocsp_verify(hx509_context context, time_t now, hx509_cert cert, int flags, const void *data, size_t length, time_t *expiration) { const Certificate *c = _hx509_get_cert(cert); OCSPBasicOCSPResponse basic; int ret; size_t i; if (now == 0) now = time(NULL); *expiration = 0; ret = parse_ocsp_basic(data, length, &basic); if (ret) { hx509_set_error_string(context, 0, ret, "Failed to parse OCSP response"); return ret; } for (i = 0; i < basic.tbsResponseData.responses.len; i++) { ret = der_heim_integer_cmp(&basic.tbsResponseData.responses.val[i].certID.serialNumber, &c->tbsCertificate.serialNumber); if (ret != 0) continue; /* verify issuer hashes hash */ ret = _hx509_verify_signature(context, NULL, &basic.tbsResponseData.responses.val[i].certID.hashAlgorithm, &c->tbsCertificate.issuer._save, &basic.tbsResponseData.responses.val[i].certID.issuerNameHash); if (ret != 0) continue; switch (basic.tbsResponseData.responses.val[i].certStatus.element) { case choice_OCSPCertStatus_good: break; case choice_OCSPCertStatus_revoked: case choice_OCSPCertStatus_unknown: continue; } /* don't allow the update to be in the future */ if (basic.tbsResponseData.responses.val[i].thisUpdate > now + context->ocsp_time_diff) continue; /* don't allow the next update to be in the past */ if (basic.tbsResponseData.responses.val[i].nextUpdate) { if (*basic.tbsResponseData.responses.val[i].nextUpdate < now) continue; *expiration = *basic.tbsResponseData.responses.val[i].nextUpdate; } else *expiration = now; free_OCSPBasicOCSPResponse(&basic); return 0; } free_OCSPBasicOCSPResponse(&basic); { hx509_name name; char *subject; ret = hx509_cert_get_subject(cert, &name); if (ret) { hx509_clear_error_string(context); goto out; } ret = hx509_name_to_string(name, &subject); hx509_name_free(&name); if (ret) { hx509_clear_error_string(context); goto out; } hx509_set_error_string(context, 0, HX509_CERT_NOT_IN_OCSP, "Certificate %s not in OCSP response " "or not good", subject); free(subject); } out: return HX509_CERT_NOT_IN_OCSP; }
int hx509_revoke_ocsp_print(hx509_context context, const char *path, FILE *out) { struct revoke_ocsp ocsp; int ret; size_t i; if (out == NULL) out = stdout; memset(&ocsp, 0, sizeof(ocsp)); ocsp.path = strdup(path); if (ocsp.path == NULL) return ENOMEM; ret = load_ocsp(context, &ocsp); if (ret) { free_ocsp(&ocsp); return ret; } fprintf(out, "signer: "); switch(ocsp.ocsp.tbsResponseData.responderID.element) { case choice_OCSPResponderID_byName: { hx509_name n; char *s; _hx509_name_from_Name(&ocsp.ocsp.tbsResponseData.responderID.u.byName, &n); hx509_name_to_string(n, &s); hx509_name_free(&n); fprintf(out, " byName: %s\n", s); free(s); break; } case choice_OCSPResponderID_byKey: { char *s; hex_encode(ocsp.ocsp.tbsResponseData.responderID.u.byKey.data, ocsp.ocsp.tbsResponseData.responderID.u.byKey.length, &s); fprintf(out, " byKey: %s\n", s); free(s); break; } default: _hx509_abort("choice_OCSPResponderID unknown"); break; } fprintf(out, "producedAt: %s\n", printable_time(ocsp.ocsp.tbsResponseData.producedAt)); fprintf(out, "replies: %d\n", ocsp.ocsp.tbsResponseData.responses.len); for (i = 0; i < ocsp.ocsp.tbsResponseData.responses.len; i++) { const char *status; switch (ocsp.ocsp.tbsResponseData.responses.val[i].certStatus.element) { case choice_OCSPCertStatus_good: status = "good"; break; case choice_OCSPCertStatus_revoked: status = "revoked"; break; case choice_OCSPCertStatus_unknown: status = "unknown"; break; default: status = "element unknown"; } fprintf(out, "\t%zu. status: %s\n", i, status); fprintf(out, "\tthisUpdate: %s\n", printable_time(ocsp.ocsp.tbsResponseData.responses.val[i].thisUpdate)); if (ocsp.ocsp.tbsResponseData.responses.val[i].nextUpdate) fprintf(out, "\tproducedAt: %s\n", printable_time(ocsp.ocsp.tbsResponseData.responses.val[i].thisUpdate)); } fprintf(out, "appended certs:\n"); if (ocsp.certs) ret = hx509_certs_iter_f(context, ocsp.certs, hx509_ci_print_names, out); free_ocsp(&ocsp); return ret; }