void cipher_init(struct iked_cipher *encr, int enc) { EVP_CipherInit_ex(encr->encr_ctx, encr->encr_priv, NULL, ibuf_data(encr->encr_key), ibuf_data(encr->encr_iv), enc); EVP_CIPHER_CTX_set_padding(encr->encr_ctx, 0); }
struct ibuf * ikev2_msg_auth(struct iked *env, struct iked_sa *sa, int response) { struct ibuf *authmsg = NULL, *nonce, *prfkey, *buf; uint8_t *ptr; struct iked_id *id; size_t tmplen; /* * Create the payload to be signed/MAC'ed for AUTH */ if (!response) { if ((nonce = sa->sa_rnonce) == NULL || (sa->sa_iid.id_type == 0) || (prfkey = sa->sa_key_iprf) == NULL || (buf = sa->sa_1stmsg) == NULL) return (NULL); id = &sa->sa_iid; } else { if ((nonce = sa->sa_inonce) == NULL || (sa->sa_rid.id_type == 0) || (prfkey = sa->sa_key_rprf) == NULL || (buf = sa->sa_2ndmsg) == NULL) return (NULL); id = &sa->sa_rid; } if ((authmsg = ibuf_dup(buf)) == NULL) return (NULL); if (ibuf_cat(authmsg, nonce) != 0) goto fail; if ((hash_setkey(sa->sa_prf, ibuf_data(prfkey), ibuf_size(prfkey))) == NULL) goto fail; if ((ptr = ibuf_advance(authmsg, hash_length(sa->sa_prf))) == NULL) goto fail; hash_init(sa->sa_prf); hash_update(sa->sa_prf, ibuf_data(id->id_buf), ibuf_size(id->id_buf)); hash_final(sa->sa_prf, ptr, &tmplen); if (tmplen != hash_length(sa->sa_prf)) goto fail; log_debug("%s: %s auth data length %zu", __func__, response ? "responder" : "initiator", ibuf_size(authmsg)); print_hex(ibuf_data(authmsg), 0, ibuf_size(authmsg)); return (authmsg); fail: ibuf_release(authmsg); return (NULL); }
int ikev2_validate_xform(struct iked_message *msg, size_t offset, size_t total, struct ikev2_transform *xfrm) { u_int8_t *msgbuf = ibuf_data(msg->msg_data); size_t xfrm_length; if (total < sizeof(*xfrm)) { log_debug("%s: payload malformed: too short for header " "(%zu < %zu)", __func__, total, sizeof(*xfrm)); return (-1); } memcpy(xfrm, msgbuf + offset, sizeof(*xfrm)); xfrm_length = betoh16(xfrm->xfrm_length); if (xfrm_length < sizeof(*xfrm)) { log_debug("%s: payload malformed: shorter than minimal header " "(%zu < %zu)", __func__, xfrm_length, sizeof(*xfrm)); return (-1); } if (total < xfrm_length) { log_debug("%s: malformed payload: too long for payload size " "(%zu < %zu)", __func__, total, xfrm_length); return (-1); } return (0); }
int ikev2_msg_send(struct iked *env, struct iked_message *msg) { struct ibuf *buf = msg->msg_data; u_int32_t natt = 0x00000000; struct ike_header *hdr; if (buf == NULL || (hdr = ibuf_seek(msg->msg_data, msg->msg_offset, sizeof(*hdr))) == NULL) return (-1); log_info("%s: %s from %s to %s, %ld bytes", __func__, print_map(hdr->ike_exchange, ikev2_exchange_map), print_host(&msg->msg_local, NULL, 0), print_host(&msg->msg_peer, NULL, 0), ibuf_length(buf)); if (msg->msg_natt || (msg->msg_sa && msg->msg_sa->sa_natt)) { if (ibuf_prepend(buf, &natt, sizeof(natt)) == -1) { log_debug("%s: failed to set NAT-T", __func__); return (-1); } } if ((sendto(msg->msg_fd, ibuf_data(buf), ibuf_size(buf), 0, (struct sockaddr *)&msg->msg_peer, msg->msg_peerlen)) == -1) { log_warn("%s: sendto", __func__); return (-1); } return (0); }
int ikev2_pld_ke(struct iked *env, struct ikev2_payload *pld, struct iked_message *msg, off_t offset) { struct ikev2_keyexchange kex; u_int8_t *buf; size_t len; u_int8_t *msgbuf = ibuf_data(msg->msg_data); memcpy(&kex, msgbuf + offset, sizeof(kex)); log_debug("%s: dh group %s reserved %d", __func__, print_map(betoh16(kex.kex_dhgroup), ikev2_xformdh_map), betoh16(kex.kex_reserved)); buf = msgbuf + offset + sizeof(kex); len = betoh16(pld->pld_length) - sizeof(*pld) - sizeof(kex); print_hex(buf, 0, len); if (ikev2_msg_frompeer(msg)) { ibuf_release(msg->msg_parent->msg_ke); if ((msg->msg_parent->msg_ke = ibuf_new(buf, len)) == NULL) { log_debug("%s: failed to get exchange", __func__); return (-1); } } return (0); }
int ca_key_serialize(EVP_PKEY *key, struct iked_id *id) { int len; u_int8_t *d; RSA *rsa; switch (key->type) { case EVP_PKEY_RSA: id->id_type = 0; id->id_offset = 0; ibuf_release(id->id_buf); if ((rsa = EVP_PKEY_get1_RSA(key)) == NULL) return (-1); if ((len = i2d_RSAPrivateKey(rsa, NULL)) <= 0) return (-1); if ((id->id_buf = ibuf_new(NULL, len)) == NULL) return (-1); d = ibuf_data(id->id_buf); if (i2d_RSAPrivateKey(rsa, &d) != len) { ibuf_release(id->id_buf); return (-1); } id->id_type = IKEV2_CERT_RSA_KEY; break; default: log_debug("%s: unsupported key type %d", __func__, key->type); return (-1); } return (0); }
int ca_setauth(struct iked *env, struct iked_sa *sa, struct ibuf *authmsg, enum privsep_procid id) { struct iovec iov[3]; int iovcnt = 3; struct iked_policy *policy = sa->sa_policy; u_int8_t type = policy->pol_auth.auth_method; if (type == IKEV2_AUTH_SHARED_KEY_MIC) { sa->sa_stateflags |= IKED_REQ_AUTH; return (ikev2_msg_authsign(env, sa, &policy->pol_auth, authmsg)); } iov[0].iov_base = &sa->sa_hdr; iov[0].iov_len = sizeof(sa->sa_hdr); iov[1].iov_base = &type; iov[1].iov_len = sizeof(type); if (type == IKEV2_AUTH_NONE) iovcnt--; else { iov[2].iov_base = ibuf_data(authmsg); iov[2].iov_len = ibuf_size(authmsg); log_debug("%s: auth length %d", __func__, ibuf_size(authmsg)); } if (proc_composev_imsg(env, id, IMSG_AUTH, -1, iov, iovcnt) == -1) return (-1); return (0); }
void ikev2_msg_retransmit_timeout(struct iked *env, void *arg) { struct iked_message *msg = arg; struct iked_sa *sa = msg->msg_sa; if (msg->msg_tries < IKED_RETRANSMIT_TRIES) { if (sendtofrom(msg->msg_fd, ibuf_data(msg->msg_data), ibuf_size(msg->msg_data), 0, (struct sockaddr *)&msg->msg_peer, msg->msg_peerlen, (struct sockaddr *)&msg->msg_local, msg->msg_locallen) == -1) { log_warn("%s: sendtofrom", __func__); sa_free(env, sa); return; } /* Exponential timeout */ timer_add(env, &msg->msg_timer, IKED_RETRANSMIT_TIMEOUT * (2 << (msg->msg_tries++))); } else { log_debug("%s: retransmit limit reached for msgid %u", __func__, msg->msg_msgid); sa_free(env, sa); } }
void ikev1_recv(struct iked *env, struct iked_message *msg) { struct ike_header *hdr; if (ibuf_size(msg->msg_data) <= sizeof(*hdr)) { log_debug("%s: short message", __func__); return; } hdr = (struct ike_header *)ibuf_data(msg->msg_data); log_debug("%s: header ispi %s rspi %s" " nextpayload %u version 0x%02x exchange %u flags 0x%02x" " msgid %u length %u", __func__, print_spi(betoh64(hdr->ike_ispi), 8), print_spi(betoh64(hdr->ike_rspi), 8), hdr->ike_nextpayload, hdr->ike_version, hdr->ike_exchange, hdr->ike_flags, betoh32(hdr->ike_msgid), betoh32(hdr->ike_length)); log_debug("%s: IKEv1 not supported", __func__); }
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_validate_auth(struct iked_message *msg, size_t offset, size_t left, struct ikev2_payload *pld, struct ikev2_auth *auth) { u_int8_t *msgbuf = ibuf_data(msg->msg_data); size_t pld_length; pld_length = betoh16(pld->pld_length); if (pld_length < sizeof(*pld) + sizeof(*auth)) { log_debug("%s: malformed payload: specified length smaller " "than minimum size (%zu < %zu)", __func__, pld_length, sizeof(*pld) + sizeof(*auth)); return (-1); } /* This will actually be caught by earlier checks. */ if (left < sizeof(*auth)) { log_debug("%s: malformed payload: too short for header " "(%zu < %zu)", __func__, left, sizeof(*auth)); return (-1); } memcpy(auth, msgbuf + offset, sizeof(*auth)); return (0); }
int ikev2_msg_send(struct iked *env, struct iked_message *msg) { struct iked_sa *sa = msg->msg_sa; struct ibuf *buf = msg->msg_data; u_int32_t natt = 0x00000000; int isnatt = 0; struct ike_header *hdr; struct iked_message *m; if (buf == NULL || (hdr = ibuf_seek(msg->msg_data, msg->msg_offset, sizeof(*hdr))) == NULL) return (-1); isnatt = (msg->msg_natt || (msg->msg_sa && msg->msg_sa->sa_natt)); log_info("%s: %s from %s to %s, %ld bytes%s", __func__, print_map(hdr->ike_exchange, ikev2_exchange_map), print_host(&msg->msg_local, NULL, 0), print_host(&msg->msg_peer, NULL, 0), ibuf_length(buf), isnatt ? ", NAT-T" : ""); if (isnatt) { if (ibuf_prepend(buf, &natt, sizeof(natt)) == -1) { log_debug("%s: failed to set NAT-T", __func__); return (-1); } msg->msg_offset += sizeof(natt); } if ((sendto(msg->msg_fd, ibuf_data(buf), ibuf_size(buf), 0, (struct sockaddr *)&msg->msg_peer, msg->msg_peerlen)) == -1) { log_warn("%s: sendto", __func__); return (-1); } if (!sa) return (0); if ((m = ikev2_msg_copy(env, msg)) == NULL) { log_debug("%s: failed to copy a message", __func__); return (-1); } m->msg_exchange = hdr->ike_exchange; if (hdr->ike_flags & IKEV2_FLAG_RESPONSE) { TAILQ_INSERT_TAIL(&sa->sa_responses, m, msg_entry); timer_initialize(env, &m->msg_timer, ikev2_msg_response_timeout, m); timer_register(env, &m->msg_timer, IKED_RESPONSE_TIMEOUT); } else { TAILQ_INSERT_TAIL(&sa->sa_requests, m, msg_entry); timer_initialize(env, &m->msg_timer, ikev2_msg_retransmit_timeout, m); timer_register(env, &m->msg_timer, IKED_RETRANSMIT_TIMEOUT); } return (0); }
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 ikev2_msg_integr(struct iked *env, struct iked_sa *sa, struct ibuf *src) { int ret = -1; size_t integrlen, tmplen; struct ibuf *integr, *prf, *tmp = NULL; u_int8_t *ptr; log_debug("%s: message length %d", __func__, ibuf_size(src)); print_hex(ibuf_data(src), 0, ibuf_size(src)); if (sa == NULL || sa->sa_integr == NULL) { log_debug("%s: invalid SA", __func__); return (-1); } if (sa->sa_hdr.sh_initiator) { integr = sa->sa_key_iauth; prf = sa->sa_key_iprf; } else { integr = sa->sa_key_rauth; prf = sa->sa_key_rprf; } integrlen = hash_length(sa->sa_integr); log_debug("%s: integrity checksum length %d", __func__, integrlen); /* * Validate packet checksum */ if ((tmp = ibuf_new(NULL, hash_keylength(sa->sa_integr))) == NULL) goto done; hash_setkey(sa->sa_integr, ibuf_data(integr), ibuf_size(integr)); hash_init(sa->sa_integr); hash_update(sa->sa_integr, ibuf_data(src), ibuf_size(src) - integrlen); hash_final(sa->sa_integr, ibuf_data(tmp), &tmplen); if (tmplen != integrlen) { log_debug("%s: hash failure", __func__); goto done; } if ((ptr = ibuf_seek(src, ibuf_size(src) - integrlen, integrlen)) == NULL) goto done; memcpy(ptr, ibuf_data(tmp), tmplen); print_hex(ibuf_data(tmp), 0, ibuf_size(tmp)); ret = 0; done: ibuf_release(tmp); return (ret); }
int ikev2_pld_certreq(struct iked *env, struct ikev2_payload *pld, struct iked_message *msg, size_t offset, size_t left) { struct iked_sa *sa = msg->msg_sa; struct ikev2_cert cert; u_int8_t *buf; ssize_t len; u_int8_t *msgbuf = ibuf_data(msg->msg_data); if (ikev2_validate_certreq(msg, offset, left, pld, &cert)) return (-1); offset += sizeof(cert); buf = msgbuf + offset; len = betoh16(pld->pld_length) - sizeof(*pld) - sizeof(cert); log_debug("%s: type %s length %zd", __func__, print_map(cert.cert_type, ikev2_cert_map), len); /* This will actually be caught by earlier checks. */ if (len < 0) { log_debug("%s: invalid certificate request length", __func__); return (-1); } print_hex(buf, 0, len); if (!ikev2_msg_frompeer(msg)) return (0); if (cert.cert_type == IKEV2_CERT_X509_CERT) { if (!len || (len % SHA_DIGEST_LENGTH) != 0) { log_debug("%s: invalid certificate request", __func__); return (-1); } } if (msg->msg_sa == NULL) return (-1); /* Optional certreq for PSK */ if (sa->sa_hdr.sh_initiator) sa->sa_stateinit |= IKED_REQ_CERT; else sa->sa_statevalid |= IKED_REQ_CERT; ca_setreq(env, &sa->sa_hdr, &sa->sa_policy->pol_localid, cert.cert_type, buf, len, PROC_CERT); return (0); }
int ikev2_msg_retransmit_response(struct iked *env, struct iked_sa *sa, struct iked_message *msg) { if ((sendto(msg->msg_fd, ibuf_data(msg->msg_data), ibuf_size(msg->msg_data), 0, (struct sockaddr *)&msg->msg_peer, msg->msg_peerlen)) == -1) { log_warn("%s: sendto", __func__); return (-1); } timer_add(env, &msg->msg_timer, IKED_RESPONSE_TIMEOUT); return (0); }
int ikev2_validate_attr(struct iked_message *msg, size_t offset, size_t total, struct ikev2_attribute *attr) { u_int8_t *msgbuf = ibuf_data(msg->msg_data); if (total < sizeof(*attr)) { log_debug("%s: payload malformed: too short for header " "(%zu < %zu)", __func__, total, sizeof(*attr)); return (-1); } memcpy(attr, msgbuf + offset, sizeof(*attr)); return (0); }
int ikev2_pld_attr(struct iked *env, struct ikev2_transform *xfrm, struct iked_message *msg, size_t offset, size_t total) { struct ikev2_attribute attr; u_int type; u_int8_t *msgbuf = ibuf_data(msg->msg_data); int ret = 0; size_t attr_length; if (ikev2_validate_attr(msg, offset, total, &attr)) return (-1); type = betoh16(attr.attr_type) & ~IKEV2_ATTRAF_TV; log_debug("%s: attribute type %s length %d total %zu", __func__, print_map(type, ikev2_attrtype_map), betoh16(attr.attr_length), total); if (betoh16(attr.attr_type) & IKEV2_ATTRAF_TV) { /* Type-Value attribute */ offset += sizeof(attr); total -= sizeof(attr); if (type == IKEV2_ATTRTYPE_KEY_LENGTH) msg->msg_attrlength = betoh16(attr.attr_length); } else { /* Type-Length-Value attribute */ attr_length = betoh16(attr.attr_length); if (total < attr_length) { log_debug("%s: payload malformed: attribute larger " "than actual payload (%zu < %zu)", __func__, total, attr_length); return (-1); } print_hex(msgbuf, offset + sizeof(attr), attr_length - sizeof(attr)); offset += attr_length; total -= attr_length; } if (total > 0) { /* Next attribute */ ret = ikev2_pld_attr(env, xfrm, msg, offset, total); } return (ret); }
int ikev2_pld_e(struct iked *env, struct ikev2_payload *pld, struct iked_message *msg, off_t offset) { struct iked_sa *sa = msg->msg_sa; struct ibuf *e = NULL; u_int8_t *msgbuf = ibuf_data(msg->msg_data); struct iked_message emsg; u_int8_t *buf; size_t len; int ret = -1; buf = msgbuf + offset; len = betoh16(pld->pld_length) - sizeof(*pld); if ((e = ibuf_new(buf, len)) == NULL) goto done; if (ikev2_msg_frompeer(msg)) { e = ikev2_msg_decrypt(env, msg->msg_sa, msg->msg_data, e); } else { sa->sa_hdr.sh_initiator = sa->sa_hdr.sh_initiator ? 0 : 1; e = ikev2_msg_decrypt(env, msg->msg_sa, msg->msg_data, e); sa->sa_hdr.sh_initiator = sa->sa_hdr.sh_initiator ? 0 : 1; } if (e == NULL) goto done; /* * Parse decrypted payload */ bzero(&emsg, sizeof(emsg)); memcpy(&emsg, msg, sizeof(*msg)); emsg.msg_data = e; emsg.msg_e = 1; emsg.msg_parent = msg; TAILQ_INIT(&emsg.msg_proposals); ret = ikev2_pld_payloads(env, &emsg, 0, ibuf_size(e), pld->pld_nextpayload, 0); done: ibuf_release(e); return (ret); }
int ca_setreq(struct iked *env, struct iked_sa *sa, struct iked_static_id *localid, uint8_t type, uint8_t *data, size_t len, enum privsep_procid procid) { struct iovec iov[4]; int iovcnt = 0; struct iked_static_id idb; struct iked_id id; int ret = -1; /* Convert to a static Id */ bzero(&id, sizeof(id)); if (ikev2_policy2id(localid, &id, 1) != 0) return (-1); bzero(&idb, sizeof(idb)); idb.id_type = id.id_type; idb.id_offset = id.id_offset; idb.id_length = ibuf_length(id.id_buf); memcpy(&idb.id_data, ibuf_data(id.id_buf), ibuf_length(id.id_buf)); iov[iovcnt].iov_base = &idb; iov[iovcnt].iov_len = sizeof(idb); iovcnt++; iov[iovcnt].iov_base = &sa->sa_hdr; iov[iovcnt].iov_len = sizeof(sa->sa_hdr); iovcnt++; iov[iovcnt].iov_base = &type; iov[iovcnt].iov_len = sizeof(type); iovcnt++; iov[iovcnt].iov_base = data; iov[iovcnt].iov_len = len; iovcnt++; if (proc_composev(&env->sc_ps, procid, IMSG_CERTREQ, iov, iovcnt) == -1) goto done; sa_stateflags(sa, IKED_REQ_CERTREQ); ret = 0; done: ibuf_release(id.id_buf); return (ret); }
int ikev2_pld_auth(struct iked *env, struct ikev2_payload *pld, struct iked_message *msg, size_t offset, size_t left) { struct ikev2_auth auth; struct iked_id *idp; u_int8_t *buf; size_t len; struct iked_sa *sa = msg->msg_sa; u_int8_t *msgbuf = ibuf_data(msg->msg_data); if (ikev2_validate_auth(msg, offset, left, pld, &auth)) return (-1); offset += sizeof(auth); buf = msgbuf + offset; len = betoh16(pld->pld_length) - sizeof(*pld) - sizeof(auth); log_debug("%s: method %s length %zu", __func__, print_map(auth.auth_method, ikev2_auth_map), len); print_hex(buf, 0, len); if (!ikev2_msg_frompeer(msg)) return (0); /* The AUTH payload indicates if the responder wants EAP or not */ if (!sa_stateok(sa, IKEV2_STATE_EAP)) sa_state(env, sa, IKEV2_STATE_AUTH_REQUEST); idp = &msg->msg_parent->msg_auth; if (idp->id_type) { log_debug("%s: duplicate auth payload", __func__); return (-1); } ibuf_release(idp->id_buf); idp->id_type = auth.auth_method; idp->id_offset = 0; if ((idp->id_buf = ibuf_new(buf, len)) == NULL) return (-1); return (0); }
int ca_privkey_serialize(EVP_PKEY *key, struct iked_id *id) { RSA *rsa = NULL; uint8_t *d; int len = 0; int ret = -1; switch (key->type) { case EVP_PKEY_RSA: id->id_type = 0; id->id_offset = 0; ibuf_release(id->id_buf); if ((rsa = EVP_PKEY_get1_RSA(key)) == NULL) goto done; if ((len = i2d_RSAPrivateKey(rsa, NULL)) <= 0) goto done; if ((id->id_buf = ibuf_new(NULL, len)) == NULL) goto done; d = ibuf_data(id->id_buf); if (i2d_RSAPrivateKey(rsa, &d) != len) { ibuf_release(id->id_buf); goto done; } id->id_type = IKEV2_CERT_RSA_KEY; break; default: log_debug("%s: unsupported key type %d", __func__, key->type); return (-1); } log_debug("%s: type %s length %d", __func__, print_map(id->id_type, ikev2_cert_map), len); ret = 0; done: if (rsa != NULL) RSA_free(rsa); return (ret); }
int ikev2_pld_certreq(struct iked *env, struct ikev2_payload *pld, struct iked_message *msg, off_t offset) { struct iked_sa *sa = msg->msg_sa; struct ikev2_cert cert; u_int8_t *buf; size_t len; u_int8_t *msgbuf = ibuf_data(msg->msg_data); memcpy(&cert, msgbuf + offset, sizeof(cert)); offset += sizeof(cert); buf = msgbuf + offset; len = betoh16(pld->pld_length) - sizeof(*pld) - sizeof(cert); log_debug("%s: type %s signatures length %d", __func__, print_map(cert.cert_type, ikev2_cert_map), len); print_hex(buf, 0, len); if (!ikev2_msg_frompeer(msg)) return (0); if (!len || (len % SHA_DIGEST_LENGTH) != 0) { log_debug("%s: invalid certificate request", __func__); return (-1); } if (msg->msg_sa == NULL) return (-1); /* Optional certreq for PSK */ if (sa->sa_hdr.sh_initiator) sa->sa_stateinit |= IKED_REQ_CERT; else sa->sa_statevalid |= IKED_REQ_CERT; ca_setreq(env, &sa->sa_hdr, &sa->sa_policy->pol_localid, cert.cert_type, buf, len, PROC_CERT); return (0); }
int ca_setcert(struct iked *env, struct iked_sahdr *sh, struct iked_id *id, u_int8_t type, u_int8_t *data, size_t len, enum privsep_procid procid) { struct iovec iov[4]; int iovcnt = 0; struct iked_static_id idb; /* Must send the cert and a valid Id to the ca process */ if (procid == PROC_CERT) { if (id == NULL || id->id_type == IKEV2_ID_NONE || ibuf_length(id->id_buf) > IKED_ID_SIZE) return (-1); bzero(&idb, sizeof(idb)); /* Convert to a static Id */ idb.id_type = id->id_type; idb.id_offset = id->id_offset; idb.id_length = ibuf_length(id->id_buf); memcpy(&idb.id_data, ibuf_data(id->id_buf), ibuf_length(id->id_buf)); iov[iovcnt].iov_base = &idb; iov[iovcnt].iov_len = sizeof(idb); iovcnt++; } iov[iovcnt].iov_base = sh; iov[iovcnt].iov_len = sizeof(*sh); iovcnt++; iov[iovcnt].iov_base = &type; iov[iovcnt].iov_len = sizeof(type); iovcnt++; iov[iovcnt].iov_base = data; iov[iovcnt].iov_len = len; iovcnt++; if (proc_composev_imsg(&env->sc_ps, procid, -1, IMSG_CERT, -1, iov, iovcnt) == -1) return (-1); return (0); }
int ikev2_pld_ke(struct iked *env, struct ikev2_payload *pld, struct iked_message *msg, size_t offset, size_t left) { struct ikev2_keyexchange kex; u_int8_t *buf; size_t len; u_int8_t *msgbuf = ibuf_data(msg->msg_data); if (ikev2_validate_ke(msg, offset, left, pld, &kex)) return (-1); log_debug("%s: dh group %s reserved %d", __func__, print_map(betoh16(kex.kex_dhgroup), ikev2_xformdh_map), betoh16(kex.kex_reserved)); buf = msgbuf + offset + sizeof(kex); len = betoh16(pld->pld_length) - sizeof(*pld) - sizeof(kex); if (len == 0) { log_debug("%s: malformed payload: no KE data given", __func__); return (-1); } /* This will actually be caught by earlier checks. */ if (left < len) { log_debug("%s: malformed payload: smaller than specified " "(%zu < %zu)", __func__, left, len); return (-1); } print_hex(buf, 0, len); if (ikev2_msg_frompeer(msg)) { ibuf_release(msg->msg_parent->msg_ke); if ((msg->msg_parent->msg_ke = ibuf_new(buf, len)) == NULL) { log_debug("%s: failed to get exchange", __func__); return (-1); } } return (0); }
int ikev2_pld_cp(struct iked *env, struct ikev2_payload *pld, struct iked_message *msg, size_t offset, size_t left) { struct ikev2_cp cp; struct ikev2_cfg *cfg; u_int8_t *buf; size_t len, i; u_int8_t *msgbuf = ibuf_data(msg->msg_data); struct iked_sa *sa = msg->msg_sa; if (ikev2_validate_cp(msg, offset, left, pld, &cp)) return (-1); offset += sizeof(cp); buf = msgbuf + offset; len = betoh16(pld->pld_length) - sizeof(*pld) - sizeof(cp); log_debug("%s: type %s length %zu", __func__, print_map(cp.cp_type, ikev2_cp_map), len); print_hex(buf, 0, len); for (i = 0; i < len;) { cfg = (struct ikev2_cfg *)(buf + i); log_debug("%s: %s 0x%04x length %d", __func__, print_map(betoh16(cfg->cfg_type), ikev2_cfg_map), betoh16(cfg->cfg_type), betoh16(cfg->cfg_length)); i += betoh16(cfg->cfg_length) + sizeof(*cfg); } if (!ikev2_msg_frompeer(msg)) return (0); if (sa) sa->sa_cp = cp.cp_type; return (0); }
int ikev2_pld_cert(struct iked *env, struct ikev2_payload *pld, struct iked_message *msg, size_t offset, size_t left) { struct ikev2_cert cert; u_int8_t *buf; size_t len; struct iked_id *certid; u_int8_t *msgbuf = ibuf_data(msg->msg_data); if (ikev2_validate_cert(msg, offset, left, pld, &cert)) return (-1); offset += sizeof(cert); buf = msgbuf + offset; len = betoh16(pld->pld_length) - sizeof(*pld) - sizeof(cert); log_debug("%s: type %s length %zu", __func__, print_map(cert.cert_type, ikev2_cert_map), len); print_hex(buf, 0, len); if (!ikev2_msg_frompeer(msg)) return (0); certid = &msg->msg_parent->msg_cert; if (certid->id_type) { log_debug("%s: duplicate cert payload", __func__); return (-1); } if ((certid->id_buf = ibuf_new(buf, len)) == NULL) { log_debug("%s: failed to save cert", __func__); return (-1); } certid->id_type = cert.cert_type; certid->id_offset = 0; return (0); }
int dsa_init(struct iked_dsa *dsa, const void *buf, size_t len) { int ret; if (dsa->dsa_hmac) { if (!HMAC_Init_ex(dsa->dsa_ctx, ibuf_data(dsa->dsa_keydata), ibuf_length(dsa->dsa_keydata), dsa->dsa_priv, NULL)) return (-1); return (0); } if (dsa->dsa_sign) ret = EVP_SignInit_ex(dsa->dsa_ctx, dsa->dsa_priv, NULL); else { if ((ret = _dsa_verify_init(dsa, buf, len)) != 0) return (ret); ret = EVP_VerifyInit_ex(dsa->dsa_ctx, dsa->dsa_priv, NULL); } return (ret ? 0 : -1); }
int ikev2_validate_pld(struct iked_message *msg, size_t offset, size_t left, struct ikev2_payload *pld) { u_int8_t *msgbuf = ibuf_data(msg->msg_data); size_t pld_length; /* We need at least the generic header. */ if (left < sizeof(*pld)) { log_debug("%s: malformed payload: too short for generic " "header (%zu < %zu)", __func__, left, sizeof(*pld)); return (-1); } memcpy(pld, msgbuf + offset, sizeof(*pld)); /* * We need at least the specified number of bytes. * pld_length is the full size of the payload including * the generic payload header. */ pld_length = betoh16(pld->pld_length); if (left < pld_length) { log_debug("%s: malformed payload: shorter than specified " "(%zu < %zu)", __func__, left, pld_length); return (-1); } /* * Sanity check the specified payload size, it must * be at last the size of the generic payload header. */ if (pld_length < sizeof(*pld)) { log_debug("%s: malformed payload: shorter than minimum " "header size (%zu < %zu)", __func__, pld_length, sizeof(*pld)); return (-1); } return (0); }
int ikev2_pld_attr(struct iked *env, struct ikev2_transform *xfrm, struct iked_message *msg, off_t offset, int total) { struct ikev2_attribute attr; u_int type; u_int8_t *msgbuf = ibuf_data(msg->msg_data); memcpy(&attr, msgbuf + offset, sizeof(attr)); type = betoh16(attr.attr_type) & ~IKEV2_ATTRAF_TV; log_debug("%s: attribute type %s length %d total %d", __func__, print_map(type, ikev2_attrtype_map), betoh16(attr.attr_length), total); if (betoh16(attr.attr_type) & IKEV2_ATTRAF_TV) { /* Type-Value attribute */ offset += sizeof(attr); total -= sizeof(attr); if (type == IKEV2_ATTRTYPE_KEY_LENGTH) msg->msg_attrlength = betoh16(attr.attr_length); } else { /* Type-Length-Value attribute */ print_hex(msgbuf, offset + sizeof(attr), betoh16(attr.attr_length) - sizeof(attr)); offset += betoh16(attr.attr_length); total -= betoh16(attr.attr_length); } if (total > 0) { /* Next attribute */ ikev2_pld_attr(env, xfrm, msg, offset, total); } return (0); }