int ca_x509_subjectaltname_cmp(X509 *cert, struct iked_static_id *id) { struct iked_id sanid; char idstr[IKED_ID_SIZE]; int ret = -1; bzero(&sanid, sizeof(sanid)); if (ca_x509_subjectaltname(cert, &sanid) != 0) return (-1); ikev2_print_id(&sanid, idstr, sizeof(idstr)); /* Compare id types, length and data */ if ((id->id_type != sanid.id_type) || ((ssize_t)ibuf_size(sanid.id_buf) != (id->id_length - id->id_offset)) || (memcmp(id->id_data + id->id_offset, ibuf_data(sanid.id_buf), ibuf_size(sanid.id_buf)) != 0)) { log_debug("%s: %s mismatched", __func__, idstr); goto done; } ret = 0; done: ibuf_release(sanid.id_buf); return (ret); }
int ikev2_pld_id(struct iked *env, struct ikev2_payload *pld, struct iked_message *msg, size_t offset, size_t left, u_int payload) { u_int8_t *ptr; struct ikev2_id id; size_t len; struct iked_id *idp, idb; struct iked_sa *sa = msg->msg_sa; u_int8_t *msgbuf = ibuf_data(msg->msg_data); char idstr[IKED_ID_SIZE]; if (ikev2_validate_id(msg, offset, left, pld, &id)) return (-1); bzero(&idb, sizeof(idb)); /* Don't strip the Id payload header */ ptr = msgbuf + offset; len = betoh16(pld->pld_length) - sizeof(*pld); idb.id_type = id.id_type; idb.id_offset = sizeof(id); if ((idb.id_buf = ibuf_new(ptr, len)) == NULL) return (-1); if (ikev2_print_id(&idb, idstr, sizeof(idstr)) == -1) { log_debug("%s: malformed id", __func__); return (-1); } log_debug("%s: id %s length %zu", __func__, idstr, len); if (!ikev2_msg_frompeer(msg)) { ibuf_release(idb.id_buf); return (0); } if (!((sa->sa_hdr.sh_initiator && payload == IKEV2_PAYLOAD_IDr) || (!sa->sa_hdr.sh_initiator && payload == IKEV2_PAYLOAD_IDi))) { log_debug("%s: unexpected id payload", __func__); return (0); } idp = &msg->msg_parent->msg_id; if (idp->id_type) { log_debug("%s: duplicate id payload", __func__); return (-1); } idp->id_buf = idb.id_buf; idp->id_offset = idb.id_offset; idp->id_type = idb.id_type; return (0); }
int ca_x509_subjectaltname(X509 *cert, struct iked_id *id) { X509_EXTENSION *san; uint8_t sanhdr[4], *data; int ext, santype, sanlen; char idstr[IKED_ID_SIZE]; if ((ext = X509_get_ext_by_NID(cert, NID_subject_alt_name, -1)) == -1 || ((san = X509_get_ext(cert, ext)) == NULL)) { log_debug("%s: did not find subjectAltName in certificate", __func__); return (-1); } if (san->value == NULL || san->value->data == NULL || san->value->length < (int)sizeof(sanhdr)) { log_debug("%s: invalid subjectAltName in certificate", __func__); return (-1); } /* This is partially based on isakmpd's x509 subjectaltname code */ data = (uint8_t *)san->value->data; memcpy(&sanhdr, data, sizeof(sanhdr)); santype = sanhdr[2] & 0x3f; sanlen = sanhdr[3]; if ((sanlen + (int)sizeof(sanhdr)) > san->value->length) { log_debug("%s: invalid subjectAltName length", __func__); return (-1); } switch (santype) { case GEN_DNS: id->id_type = IKEV2_ID_FQDN; break; case GEN_EMAIL: id->id_type = IKEV2_ID_UFQDN; break; case GEN_IPADD: if (sanlen == 4) id->id_type = IKEV2_ID_IPV4; else if (sanlen == 16) id->id_type = IKEV2_ID_IPV6; else { log_debug("%s: invalid subjectAltName IP address", __func__); return (-1); } break; default: log_debug("%s: unsupported subjectAltName type %d", __func__, santype); return (-1); } ibuf_release(id->id_buf); if ((id->id_buf = ibuf_new(data + sizeof(sanhdr), sanlen)) == NULL) { log_debug("%s: failed to get id buffer", __func__); return (-1); } id->id_offset = 0; ikev2_print_id(id, idstr, sizeof(idstr)); log_debug("%s: %s", __func__, idstr); return (0); }
int ca_validate_pubkey(struct iked *env, struct iked_static_id *id, void *data, size_t len) { BIO *rawcert = NULL; RSA *peerrsa = NULL, *localrsa = NULL; EVP_PKEY *peerkey = NULL, *localkey = NULL; int ret = -1; FILE *fp = NULL; char idstr[IKED_ID_SIZE]; char file[PATH_MAX]; struct iked_id idp; if (len == 0 && data == NULL) return (-1); switch (id->id_type) { case IKEV2_ID_IPV4: case IKEV2_ID_FQDN: case IKEV2_ID_UFQDN: case IKEV2_ID_IPV6: break; default: /* Some types like ASN1_DN will not be mapped to file names */ return (-1); } bzero(&idp, sizeof(idp)); if ((idp.id_buf = ibuf_new(id->id_data, id->id_length)) == NULL) goto done; idp.id_type = id->id_type; idp.id_offset = id->id_offset; if (ikev2_print_id(&idp, idstr, sizeof(idstr)) == -1) goto done; if (len == 0) { /* Data is already an public key */ peerkey = (EVP_PKEY *)data; } else { if ((rawcert = BIO_new_mem_buf(data, len)) == NULL) goto done; if ((peerrsa = d2i_RSAPublicKey_bio(rawcert, NULL)) == NULL) goto sslerr; if ((peerkey = EVP_PKEY_new()) == NULL) goto sslerr; if (!EVP_PKEY_set1_RSA(peerkey, peerrsa)) goto sslerr; } lc_string(idstr); if (strlcpy(file, IKED_PUBKEY_DIR, sizeof(file)) >= sizeof(file) || strlcat(file, idstr, sizeof(file)) >= sizeof(file)) goto done; if ((fp = fopen(file, "r")) == NULL) goto done; localkey = PEM_read_PUBKEY(fp, NULL, NULL, NULL); if (localkey == NULL) { /* reading PKCS #8 failed, try PEM */ rewind(fp); localrsa = PEM_read_RSAPublicKey(fp, NULL, NULL, NULL); fclose(fp); if (localrsa == NULL) goto sslerr; if ((localkey = EVP_PKEY_new()) == NULL) goto sslerr; if (!EVP_PKEY_set1_RSA(localkey, localrsa)) goto sslerr; } else { fclose(fp); } if (localkey == NULL) goto sslerr; if (!EVP_PKEY_cmp(peerkey, localkey)) goto done; log_debug("%s: valid public key in file %s", __func__, file); ret = 0; sslerr: if (ret != 0) ca_sslerror(__func__); done: ibuf_release(idp.id_buf); if (peerkey != NULL) EVP_PKEY_free(peerkey); if (localkey != NULL) EVP_PKEY_free(localkey); if (peerrsa != NULL) RSA_free(peerrsa); if (localrsa != NULL) RSA_free(localrsa); if (rawcert != NULL) BIO_free(rawcert); return (ret); }