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); }
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); }
struct ibuf * ikev2_msg_decrypt(struct iked *env, struct iked_sa *sa, struct ibuf *msg, struct ibuf *src) { ssize_t ivlen, encrlen, integrlen, blocklen, outlen, tmplen; uint8_t pad = 0, *ptr; struct ibuf *integr, *encr, *tmp = NULL, *out = NULL; off_t ivoff, encroff, integroff; if (sa == NULL || sa->sa_encr == NULL || sa->sa_integr == NULL) { log_debug("%s: invalid SA", __func__); print_hex(ibuf_data(src), 0, ibuf_size(src)); goto done; } if (!sa->sa_hdr.sh_initiator) { encr = sa->sa_key_iencr; integr = sa->sa_key_iauth; } else { encr = sa->sa_key_rencr; integr = sa->sa_key_rauth; } blocklen = cipher_length(sa->sa_encr); ivlen = cipher_ivlength(sa->sa_encr); ivoff = 0; integrlen = hash_length(sa->sa_integr); integroff = ibuf_size(src) - integrlen; encroff = ivlen; encrlen = ibuf_size(src) - integrlen - ivlen; if (encrlen < 0 || integroff < 0) { log_debug("%s: invalid integrity value", __func__); goto done; } log_debug("%s: IV length %zd", __func__, ivlen); print_hex(ibuf_data(src), 0, ivlen); log_debug("%s: encrypted payload length %zd", __func__, encrlen); print_hex(ibuf_data(src), encroff, encrlen); log_debug("%s: integrity checksum length %zd", __func__, integrlen); print_hex(ibuf_data(src), integroff, integrlen); /* * Validate packet checksum */ if ((tmp = ibuf_new(NULL, ibuf_length(integr))) == NULL) goto done; hash_setkey(sa->sa_integr, integr->buf, ibuf_length(integr)); hash_init(sa->sa_integr); hash_update(sa->sa_integr, ibuf_data(msg), ibuf_size(msg) - integrlen); hash_final(sa->sa_integr, tmp->buf, &tmplen); if (memcmp(tmp->buf, ibuf_data(src) + integroff, integrlen) != 0) { log_debug("%s: integrity check failed", __func__); goto done; } log_debug("%s: integrity check succeeded", __func__); print_hex(tmp->buf, 0, tmplen); ibuf_release(tmp); tmp = NULL; /* * Decrypt the payload and strip any padding */ if ((encrlen % blocklen) != 0) { log_debug("%s: unaligned encrypted payload", __func__); goto done; } cipher_setkey(sa->sa_encr, encr->buf, ibuf_length(encr)); cipher_setiv(sa->sa_encr, ibuf_data(src) + ivoff, ivlen); cipher_init_decrypt(sa->sa_encr); if ((out = ibuf_new(NULL, cipher_outlength(sa->sa_encr, encrlen))) == NULL) goto done; if ((outlen = ibuf_length(out)) != 0) { cipher_update(sa->sa_encr, ibuf_data(src) + encroff, encrlen, ibuf_data(out), &outlen); ptr = ibuf_seek(out, outlen - 1, 1); pad = *ptr; } log_debug("%s: decrypted payload length %zd/%zd padding %d", __func__, outlen, encrlen, pad); print_hex(ibuf_data(out), 0, ibuf_size(out)); if (ibuf_setsize(out, outlen) != 0) goto done; ibuf_release(src); return (out); done: ibuf_release(tmp); ibuf_release(out); ibuf_release(src); return (NULL); }