int ca_getcert(struct iked *env, struct imsg *imsg) { struct iked_sahdr sh; u_int8_t type; u_int8_t *ptr; size_t len; struct iked_static_id id; u_int i; struct iovec iov[2]; int iovcnt = 2, cmd, ret = 0; ptr = (u_int8_t *)imsg->data; len = IMSG_DATA_SIZE(imsg); i = sizeof(id) + sizeof(sh) + sizeof(type); if (len <= i) return (-1); memcpy(&id, ptr, sizeof(id)); if (id.id_type == IKEV2_ID_NONE) return (-1); memcpy(&sh, ptr + sizeof(id), sizeof(sh)); memcpy(&type, ptr + sizeof(id) + sizeof(sh), sizeof(u_int8_t)); ptr += i; len -= i; switch (type) { case IKEV2_CERT_X509_CERT: ret = ca_validate_cert(env, &id, ptr, len); if (ret == 0 && env->sc_ocsp_url) { ret = ocsp_validate_cert(env, &id, ptr, len, sh, type); if (ret == 0) return (0); } break; case IKEV2_CERT_RSA_KEY: ret = ca_validate_pubkey(env, &id, ptr, len); break; default: log_debug("%s: unsupported cert type %d", __func__, type); ret = -1; break; } if (ret == 0) cmd = IMSG_CERTVALID; else cmd = IMSG_CERTINVALID; iov[0].iov_base = &sh; iov[0].iov_len = sizeof(sh); iov[1].iov_base = &type; iov[1].iov_len = sizeof(type); if (proc_composev_imsg(&env->sc_ps, PROC_IKEV2, -1, cmd, -1, iov, iovcnt) == -1) return (-1); return (0); }
int ca_validate_cert(struct iked *env, struct iked_static_id *id, void *data, size_t len) { struct ca_store *store = env->sc_priv; X509_STORE_CTX csc; BIO *rawcert = NULL; X509 *cert = NULL; int ret = -1, result, error; X509_NAME *subject; const char *errstr = "failed"; if (len == 0) { /* Data is already an X509 certificate */ cert = (X509 *)data; } else { /* Convert data to X509 certificate */ if ((rawcert = BIO_new_mem_buf(data, len)) == NULL) goto done; if ((cert = d2i_X509_bio(rawcert, NULL)) == NULL) goto done; } /* Certificate needs a valid subjectName */ if ((subject = X509_get_subject_name(cert)) == NULL) { errstr = "invalid subject"; goto done; } if (id != NULL) { if ((ret = ca_validate_pubkey(env, id, X509_get_pubkey(cert), 0)) == 0) { errstr = "in public key file, ok"; goto done; } switch (id->id_type) { case IKEV2_ID_ASN1_DN: if (ca_x509_subject_cmp(cert, id) < 0) { errstr = "ASN1_DN identifier mismatch"; goto done; } break; default: if (ca_x509_subjectaltname_cmp(cert, id) != 0) { errstr = "invalid subjectAltName extension"; goto done; } break; } } bzero(&csc, sizeof(csc)); X509_STORE_CTX_init(&csc, store->ca_cas, cert, NULL); if (store->ca_cas->param->flags & X509_V_FLAG_CRL_CHECK) { X509_STORE_CTX_set_flags(&csc, X509_V_FLAG_CRL_CHECK); X509_STORE_CTX_set_flags(&csc, X509_V_FLAG_CRL_CHECK_ALL); } result = X509_verify_cert(&csc); error = csc.error; X509_STORE_CTX_cleanup(&csc); if (error != 0) { errstr = X509_verify_cert_error_string(error); goto done; } if (!result) { /* XXX should we accept self-signed certificates? */ errstr = "rejecting self-signed certificate"; goto done; } /* Success */ ret = 0; errstr = "ok"; done: if (cert != NULL) log_debug("%s: %s %.100s", __func__, cert->name, errstr); if (rawcert != NULL) { BIO_free(rawcert); if (cert != NULL) X509_free(cert); } return (ret); }