void crypto_encrypt(struct keystate *ks, u_int8_t *buf, u_int16_t len) { LOG_DBG_BUF((LOG_CRYPTO, 70, "crypto_encrypt: before encryption", buf, len)); ks->xf->encrypt(ks, buf, len); memcpy(ks->liv, buf + len - ks->xf->blocksize, ks->xf->blocksize); LOG_DBG_BUF((LOG_CRYPTO, 70, "crypto_encrypt: after encryption", buf, len)); }
void crypto_decrypt(struct keystate *ks, u_int8_t *buf, u_int16_t len) { LOG_DBG_BUF((LOG_CRYPTO, 70, "crypto_decrypt: before decryption", buf, len)); /* * XXX There is controversy about the correctness of updating the IV * like this. */ memcpy(ks->liv, buf + len - ks->xf->blocksize, ks->xf->blocksize); ks->xf->decrypt(ks, buf, len); LOG_DBG_BUF((LOG_CRYPTO, 70, "crypto_decrypt: after decryption", buf, len)); }
/* Both DSS & RSA signature authentication use this algorithm. */ static u_int8_t * sig_gen_skeyid (struct exchange *exchange, size_t *sz) { struct prf *prf; struct ipsec_exch *ie = exchange->data; u_int8_t *skeyid; unsigned char *key; key = malloc (exchange->nonce_i_len + exchange->nonce_r_len); if (!key) return 0; memcpy (key, exchange->nonce_i, exchange->nonce_i_len); memcpy (key + exchange->nonce_i_len, exchange->nonce_r, exchange->nonce_r_len); LOG_DBG ((LOG_NEGOTIATION, 80, "sig_gen_skeyid: PRF type %d, hash %d", ie->prf_type, ie->hash->type)); LOG_DBG_BUF ((LOG_NEGOTIATION, 80, "sig_gen_skeyid: SKEYID initialized with", (u_int8_t *)key, exchange->nonce_i_len + exchange->nonce_r_len)); prf = prf_alloc (ie->prf_type, ie->hash->type, key, exchange->nonce_i_len + exchange->nonce_r_len); free (key); if (!prf) return 0; *sz = prf->blocksize; skeyid = malloc (*sz); if (!skeyid) { log_error ("sig_gen_skeyid: malloc (%lu) failed", (unsigned long)*sz); prf_free (prf); return 0; } LOG_DBG ((LOG_NEGOTIATION, 80, "sig_gen_skeyid: g^xy length %lu", (unsigned long)ie->g_x_len)); LOG_DBG_BUF ((LOG_NEGOTIATION, 80, "sig_gen_skeyid: SKEYID fed with g^xy", ie->g_xy, ie->g_x_len)); prf->Init (prf->prfctx); prf->Update (prf->prfctx, ie->g_xy, ie->g_x_len); prf->Final (skeyid, prf->prfctx); prf_free (prf); return skeyid; }
/* Receive HASH and check that the exchange has been consistent. */ int ike_phase_1_recv_AUTH (struct message *msg) { struct exchange *exchange = msg->exchange; struct ipsec_exch *ie = exchange->data; struct prf *prf; struct hash *hash = ie->hash; char header[80]; size_t hashsize = hash->hashsize; int initiator = exchange->initiator; u_int8_t **hash_p, *id; size_t id_len; /* Choose the right fields to fill in */ hash_p = initiator ? &ie->hash_r : &ie->hash_i; id = initiator ? exchange->id_r : exchange->id_i; id_len = initiator ? exchange->id_r_len : exchange->id_i_len; /* The decoded hash will be in ie->hash_r or ie->hash_i */ if (ie->ike_auth->decode_hash (msg)) { message_drop (msg, ISAKMP_NOTIFY_INVALID_ID_INFORMATION, 0, 1, 0); return -1; } /* Allocate the prf and start calculating his HASH. */ prf = prf_alloc (ie->prf_type, hash->type, ie->skeyid, ie->skeyid_len); if (!prf) { /* XXX Log? */ return -1; } prf->Init (prf->prfctx); prf->Update (prf->prfctx, initiator ? ie->g_xr : ie->g_xi, ie->g_x_len); prf->Update (prf->prfctx, initiator ? ie->g_xi : ie->g_xr, ie->g_x_len); prf->Update (prf->prfctx, exchange->cookies + (initiator ? ISAKMP_HDR_RCOOKIE_OFF : ISAKMP_HDR_ICOOKIE_OFF), ISAKMP_HDR_ICOOKIE_LEN); prf->Update (prf->prfctx, exchange->cookies + (initiator ? ISAKMP_HDR_ICOOKIE_OFF : ISAKMP_HDR_RCOOKIE_OFF), ISAKMP_HDR_ICOOKIE_LEN); prf->Update (prf->prfctx, ie->sa_i_b, ie->sa_i_b_len); prf->Update (prf->prfctx, id, id_len); prf->Final (hash->digest, prf->prfctx); prf_free (prf); snprintf (header, sizeof header, "ike_phase_1_recv_AUTH: computed HASH_%c", initiator ? 'R' : 'I'); LOG_DBG_BUF ((LOG_NEGOTIATION, 80, header, hash->digest, hashsize)); /* Check that the hash we got matches the one we computed. */ if (memcmp (*hash_p, hash->digest, hashsize) != 0) { /* XXX Log? */ return -1; } return 0; }
void crypto_init_iv(struct keystate *ks, u_int8_t *buf, size_t len) { memcpy(ks->riv, buf, len); LOG_DBG_BUF((LOG_CRYPTO, 50, "crypto_init_iv: initialized IV", ks->riv, len)); }
/* Lookup a certificate by an ID blob. */ static X509 * x509_hash_find(u_int8_t *id, size_t len) { struct x509_hash *cert; u_int8_t **cid; u_int32_t *clen; int n, i, id_found; for (cert = LIST_FIRST(&x509_tab[x509_hash(id, len)]); cert; cert = LIST_NEXT(cert, link)) { if (!x509_cert_get_subjects(cert->cert, &n, &cid, &clen)) continue; id_found = 0; for (i = 0; i < n; i++) { LOG_DBG_BUF((LOG_CRYPTO, 70, "cert_cmp", id, len)); LOG_DBG_BUF((LOG_CRYPTO, 70, "cert_cmp", cid[i], clen[i])); /* * XXX This identity predicate needs to be * understood. */ if (clen[i] == len && id[0] == cid[i][0] && memcmp(id + 4, cid[i] + 4, len - 4) == 0) { id_found++; break; } } cert_free_subjects(n, cid, clen); if (!id_found) continue; LOG_DBG((LOG_CRYPTO, 70, "x509_hash_find: return X509 %p", cert->cert)); return cert->cert; } LOG_DBG((LOG_CRYPTO, 70, "x509_hash_find: no certificate matched query")); return 0; }
void crypto_update_iv(struct keystate *ks) { u_int8_t *tmp; tmp = ks->riv; ks->riv = ks->liv; ks->liv = tmp; LOG_DBG_BUF((LOG_CRYPTO, 50, "crypto_update_iv: updated IV", ks->riv, ks->xf->blocksize)); }
/* Generate the NAT-T capability marker hashes. Executed only once. */ static int nat_t_setup_hashes(void) { struct hash *hash; int n = NUMNATTCAP; int i; /* The draft says to use MD5. */ hash = hash_get(HASH_MD5); if (!hash) { /* Should never happen. */ log_print("nat_t_setup_hashes: " "could not find MD5 hash structure!"); return -1; } /* Populate isakmp_nat_t_cap with hashes. */ for (i = 0; i < n; i++) { isakmp_nat_t_cap[i].hashsize = hash->hashsize; isakmp_nat_t_cap[i].hash = malloc(hash->hashsize); if (!isakmp_nat_t_cap[i].hash) { log_error("nat_t_setup_hashes: malloc (%lu) failed", (unsigned long)hash->hashsize); goto errout; } hash->Init(hash->ctx); hash->Update(hash->ctx, (unsigned char *)isakmp_nat_t_cap[i].text, strlen(isakmp_nat_t_cap[i].text)); hash->Final(isakmp_nat_t_cap[i].hash, hash->ctx); LOG_DBG((LOG_EXCHANGE, 50, "nat_t_setup_hashes: " "MD5(\"%s\") (%lu bytes)", isakmp_nat_t_cap[i].text, (unsigned long)hash->hashsize)); LOG_DBG_BUF((LOG_EXCHANGE, 50, "nat_t_setup_hashes", isakmp_nat_t_cap[i].hash, hash->hashsize)); } return 0; errout: for (i = 0; i < n; i++) free(isakmp_nat_t_cap[i].hash); return -1; }
static int pre_shared_decode_hash (struct message *msg) { struct exchange *exchange = msg->exchange; struct ipsec_exch *ie = exchange->data; struct payload *payload; size_t hashsize = ie->hash->hashsize; char header[80]; int initiator = exchange->initiator; u_int8_t **hash_p; /* Choose the right fields to fill-in. */ hash_p = initiator ? &ie->hash_r : &ie->hash_i; payload = TAILQ_FIRST (&msg->payload[ISAKMP_PAYLOAD_HASH]); if (!payload) { log_print ("pre_shared_decode_hash: no HASH payload found"); return -1; } /* Check that the hash is of the correct size. */ if (GET_ISAKMP_GEN_LENGTH (payload->p) - ISAKMP_GEN_SZ != hashsize) return -1; /* XXX Need this hash be in the SA? */ *hash_p = malloc (hashsize); if (!*hash_p) { log_error ("pre_shared_decode_hash: malloc (%lu) failed", (unsigned long)hashsize); return -1; } memcpy (*hash_p, payload->p + ISAKMP_HASH_DATA_OFF, hashsize); snprintf (header, sizeof header, "pre_shared_decode_hash: HASH_%c", initiator ? 'R' : 'I'); LOG_DBG_BUF ((LOG_MISC, 80, header, *hash_p, hashsize)); payload->flags |= PL_MARK; return 0; }
/* * Dump the internal state of SA to the report channel, with HEADER * prepended to each line. */ void sa_dump(int cls, int level, char *header, struct sa *sa) { struct proto *proto; char spi_header[80]; int i; LOG_DBG((cls, level, "%s: %p %s phase %d doi %d flags 0x%x", header, sa, sa->name ? sa->name : "<unnamed>", sa->phase, sa->doi->id, sa->flags)); LOG_DBG((cls, level, "%s: icookie %08x%08x rcookie %08x%08x", header, decode_32(sa->cookies), decode_32(sa->cookies + 4), decode_32(sa->cookies + 8), decode_32(sa->cookies + 12))); LOG_DBG((cls, level, "%s: msgid %08x refcnt %d", header, decode_32(sa->message_id), sa->refcnt)); LOG_DBG((cls, level, "%s: life secs %llu kb %llu", header, sa->seconds, sa->kilobytes)); for (proto = TAILQ_FIRST(&sa->protos); proto; proto = TAILQ_NEXT(proto, link)) { LOG_DBG((cls, level, "%s: suite %d proto %d", header, proto->no, proto->proto)); LOG_DBG((cls, level, "%s: spi_sz[0] %d spi[0] %p spi_sz[1] %d spi[1] %p", header, proto->spi_sz[0], proto->spi[0], proto->spi_sz[1], proto->spi[1])); LOG_DBG((cls, level, "%s: %s, %s", header, !sa->doi ? "<nodoi>" : sa->doi->decode_ids("initiator id: %s, responder id: %s", sa->id_i, sa->id_i_len, sa->id_r, sa->id_r_len, 0), !sa->transport ? "<no transport>" : sa->transport->vtbl->decode_ids(sa->transport))); for (i = 0; i < 2; i++) if (proto->spi[i]) { snprintf(spi_header, sizeof spi_header, "%s: spi[%d]", header, i); LOG_DBG_BUF((cls, level, spi_header, proto->spi[i], proto->spi_sz[i])); } } }
static int pre_shared_encode_hash (struct message *msg) { struct exchange *exchange = msg->exchange; struct ipsec_exch *ie = exchange->data; size_t hashsize = ie->hash->hashsize; char header[80]; int initiator = exchange->initiator; u_int8_t *buf; buf = ipsec_add_hash_payload (msg, hashsize); if (!buf) return -1; if (ike_auth_hash (exchange, buf + ISAKMP_HASH_DATA_OFF) == -1) return -1; snprintf (header, sizeof header, "pre_shared_encode_hash: HASH_%c", initiator ? 'I' : 'R'); LOG_DBG_BUF ((LOG_MISC, 80, header, buf + ISAKMP_HASH_DATA_OFF, hashsize)); return 0; }
struct keystate * crypto_init(struct crypto_xf *xf, u_int8_t *key, u_int16_t len, enum cryptoerr *err) { struct keystate *ks; if (len < xf->keymin || len > xf->keymax) { LOG_DBG((LOG_CRYPTO, 10, "crypto_init: invalid key length %d", len)); *err = EKEYLEN; return 0; } ks = calloc(1, sizeof *ks); if (!ks) { log_error("crypto_init: calloc (1, %lu) failed", (unsigned long)sizeof *ks); *err = ENOCRYPTO; return 0; } ks->xf = xf; /* Setup the IV. */ ks->riv = ks->iv; ks->liv = ks->iv2; LOG_DBG_BUF((LOG_CRYPTO, 40, "crypto_init: key", key, len)); *err = xf->init(ks, key, len); if (*err != EOKAY) { LOG_DBG((LOG_CRYPTO, 30, "crypto_init: weak key found for %s", xf->name)); free(ks); return 0; } return ks; }
/* Receive ID. */ int ike_phase_1_recv_ID (struct message *msg) { struct exchange *exchange = msg->exchange; struct payload *payload; char header[80], *rs = 0, *rid = 0, *p; int initiator = exchange->initiator; u_int8_t **id, id_type; size_t *id_len, sz; struct sockaddr *sa; payload = TAILQ_FIRST (&msg->payload[ISAKMP_PAYLOAD_ID]); if (exchange->name) rs = conf_get_str (exchange->name, "Remote-ID"); if (rs) { sz = ipsec_id_size (rs, &id_type); if (sz == -1) { log_print ("ike_phase_1_recv_ID: could not handle specified " "Remote-ID [%s]", rs); return -1; } rid = malloc (sz); if (!rid) { log_error ("ike_phase_1_recv_ID: malloc (%lu) failed", (unsigned long)sz); return -1; } switch (id_type) { case IPSEC_ID_IPV4_ADDR: case IPSEC_ID_IPV6_ADDR: p = conf_get_str (rs, "Address"); if (!p) { log_print ("ike_phase_1_recv_ID: " "failed to get Address in Remote-ID section [%s]", rs); free (rid); return -1; } if (text2sockaddr (p, 0, &sa) == -1) { log_print ("ike_phase_1_recv_ID: failed to parse address %s", p); free (rid); return -1; } if ((id_type == IPSEC_ID_IPV4_ADDR && sa->sa_family != AF_INET) || (id_type == IPSEC_ID_IPV6_ADDR && sa->sa_family != AF_INET6)) { log_print ("ike_phase_1_recv_ID: " "address %s not of expected family", p); free (rid); free (sa); return -1; } memcpy (rid, sockaddr_addrdata (sa), sockaddr_addrlen (sa)); free (sa); break; case IPSEC_ID_FQDN: case IPSEC_ID_USER_FQDN: case IPSEC_ID_KEY_ID: p = conf_get_str (rs, "Name"); if (!p) { log_print ("ike_phase_1_recv_ID: " "failed to get Name in Remote-ID section [%s]", rs); free (rid); return -1; } memcpy (rid, p, sz); break; default: log_print ("ike_phase_1_recv_ID: unsupported ID type %d", id_type); free (rid); return -1; } /* Compare expected/desired and received remote ID */ if (bcmp (rid, payload->p + ISAKMP_ID_DATA_OFF, sz)) { free (rid); log_print ("ike_phase_1_recv_ID: " "received remote ID other than expected %s", p); return -1; } free (rid); } /* Choose the right fields to fill in */ id = initiator ? &exchange->id_r : &exchange->id_i; id_len = initiator ? &exchange->id_r_len : &exchange->id_i_len; *id_len = GET_ISAKMP_GEN_LENGTH (payload->p) - ISAKMP_GEN_SZ; *id = malloc (*id_len); if (!*id) { log_error ("ike_phase_1_recv_ID: malloc (%lu) failed", (unsigned long)*id_len); return -1; } memcpy (*id, payload->p + ISAKMP_GEN_SZ, *id_len); snprintf (header, sizeof header, "ike_phase_1_recv_ID: %s", constant_name (ipsec_id_cst, GET_ISAKMP_ID_TYPE (payload->p))); LOG_DBG_BUF ((LOG_NEGOTIATION, 40, header, payload->p + ISAKMP_ID_DATA_OFF, *id_len + ISAKMP_GEN_SZ - ISAKMP_ID_DATA_OFF)); payload->flags |= PL_MARK; return 0; }
/* Decrypt the HASH in SIG, we already need a parsed ID payload. */ static int rsa_sig_decode_hash (struct message *msg) { struct cert_handler *handler; struct exchange *exchange = msg->exchange; struct ipsec_exch *ie = exchange->data; struct payload *p; void *cert = 0; u_int8_t *rawcert = 0; u_int32_t rawcertlen; RSA *key = 0; size_t hashsize = ie->hash->hashsize; char header[80]; int len; int initiator = exchange->initiator; u_int8_t **hash_p, **id_cert, *id; u_int32_t *id_cert_len; size_t id_len; int found = 0, n, i, id_found; #if defined (USE_DNSSEC) u_int8_t *rawkey = 0; u_int32_t rawkeylen; #endif /* Choose the right fields to fill-in. */ hash_p = initiator ? &ie->hash_r : &ie->hash_i; id = initiator ? exchange->id_r : exchange->id_i; id_len = initiator ? exchange->id_r_len : exchange->id_i_len; if (!id || id_len == 0) { log_print ("rsa_sig_decode_hash: ID is missing"); return -1; } /* * XXX Assume we should use the same kind of certification as the remote... * moreover, just use the first CERT payload to decide what to use. */ p = TAILQ_FIRST (&msg->payload[ISAKMP_PAYLOAD_CERT]); if (!p) handler = cert_get (ISAKMP_CERTENC_KEYNOTE); else handler = cert_get (GET_ISAKMP_CERT_ENCODING (p->p)); if (!handler) { log_print ("rsa_sig_decode_hash: cert_get (%d) failed", p ? GET_ISAKMP_CERT_ENCODING (p->p) : -1); return -1; } #if defined (USE_POLICY) && defined (USE_KEYNOTE) /* * We need the policy session initialized now, so we can add * credentials etc. */ exchange->policy_id = kn_init (); if (exchange->policy_id == -1) { log_print ("rsa_sig_decode_hash: failed to initialize policy session"); return -1; } #endif /* USE_POLICY || USE_KEYNOTE */ /* Obtain a certificate from our certificate storage. */ if (handler->cert_obtain (id, id_len, 0, &rawcert, &rawcertlen)) { if (handler->id == ISAKMP_CERTENC_X509_SIG) { cert = handler->cert_get (rawcert, rawcertlen); if (!cert) LOG_DBG ((LOG_CRYPTO, 50, "rsa_sig_decode_hash: certificate malformed")); else { if (!handler->cert_get_key (cert, &key)) { log_print ("rsa_sig_decode_hash: " "decoding certificate failed"); handler->cert_free (cert); } else { found++; LOG_DBG ((LOG_CRYPTO, 40, "rsa_sig_decode_hash: using cert of type %d", handler->id)); exchange->recv_cert = cert; exchange->recv_certtype = handler->id; #if defined (USE_POLICY) x509_generate_kn (exchange->policy_id, cert); #endif /* USE_POLICY */ } } } else if (handler->id == ISAKMP_CERTENC_KEYNOTE) handler->cert_insert (exchange->policy_id, rawcert); free (rawcert); } /* * Walk over potential CERT payloads in this message. * XXX I believe this is the wrong spot for this. CERTs can appear * anytime. */ for (p = TAILQ_FIRST (&msg->payload[ISAKMP_PAYLOAD_CERT]); p; p = TAILQ_NEXT (p, link)) { p->flags |= PL_MARK; /* When we have found a key, just walk over the rest, marking them. */ if (found) continue; handler = cert_get (GET_ISAKMP_CERT_ENCODING (p->p)); if (!handler) { LOG_DBG ((LOG_MISC, 30, "rsa_sig_decode_hash: no handler for %s CERT encoding", constant_name (isakmp_certenc_cst, GET_ISAKMP_CERT_ENCODING (p->p)))); continue; } cert = handler->cert_get (p->p + ISAKMP_CERT_DATA_OFF, GET_ISAKMP_GEN_LENGTH (p->p) - ISAKMP_CERT_DATA_OFF); if (!cert) { log_print ("rsa_sig_decode_hash: can not get data from CERT"); continue; } if (!handler->cert_validate (cert)) { handler->cert_free (cert); log_print ("rsa_sig_decode_hash: received CERT can't be validated"); continue; } if (GET_ISAKMP_CERT_ENCODING (p->p) == ISAKMP_CERTENC_X509_SIG) { if (!handler->cert_get_subjects (cert, &n, &id_cert, &id_cert_len)) { handler->cert_free (cert); log_print ("rsa_sig_decode_hash: can not get subject from CERT"); continue; } id_found = 0; for (i = 0; i < n; i++) if (id_cert_len[i] == id_len && id[0] == id_cert[i][0] && memcmp (id + 4, id_cert[i] + 4, id_len - 4) == 0) { id_found++; break; } if (!id_found) { handler->cert_free (cert); log_print ("rsa_sig_decode_hash: no CERT subject match the ID"); free (id_cert); continue; } cert_free_subjects (n, id_cert, id_cert_len); } if (!handler->cert_get_key (cert, &key)) { handler->cert_free (cert); log_print ("rsa_sig_decode_hash: decoding payload CERT failed"); continue; } /* We validated the cert, cache it for later use. */ handler->cert_insert (exchange->policy_id, cert); exchange->recv_cert = cert; exchange->recv_certtype = GET_ISAKMP_CERT_ENCODING (p->p); #if defined (USE_POLICY) && defined (USE_KEYNOTE) if (exchange->recv_certtype == ISAKMP_CERTENC_KEYNOTE) { struct keynote_deckey dc; char *pp; int dclen; dc.dec_algorithm = KEYNOTE_ALGORITHM_RSA; dc.dec_key = key; pp = kn_encode_key (&dc, INTERNAL_ENC_PKCS1, ENCODING_HEX, KEYNOTE_PUBLIC_KEY); if (pp == NULL) { kn_free_key (&dc); log_print ("rsa_sig_decode_hash: failed to ASCII-encode key"); return -1; } dclen = strlen (pp) + sizeof "rsa-hex:"; exchange->keynote_key = calloc (dclen, sizeof (char)); if (!exchange->keynote_key) { free (pp); kn_free_key (&dc); log_print ("rsa_sig_decode_hash: failed to allocate %d bytes", dclen); return -1; } snprintf (exchange->keynote_key, dclen, "rsa-hex:%s", pp); free (pp); } #endif found++; } #if defined (USE_DNSSEC) /* If no certificate provided a key, try to find a validated DNSSEC KEY. */ if (!found) { rawkey = dns_get_key (IKE_AUTH_RSA_SIG, msg, &rawkeylen); /* We need to convert 'void *rawkey' into 'RSA *key'. */ if (dns_RSA_dns_to_x509 (rawkey, rawkeylen, &key) == 0) found++; else log_print ("rsa_sig_decode_hash: KEY to RSA key conversion failed"); if (rawkey) free (rawkey); } #endif /* USE_DNSSEC */ #if defined (USE_RAWKEY) /* If we still have not found a key, try to read it from a file. */ if (!found) if (get_raw_key_from_file (IKE_AUTH_RSA_SIG, id, id_len, &key) != -1) found++; #endif if (!found) { log_print ("rsa_sig_decode_hash: no public key found"); return -1; } p = TAILQ_FIRST (&msg->payload[ISAKMP_PAYLOAD_SIG]); if (!p) { log_print ("rsa_sig_decode_hash: missing signature payload"); RSA_free (key); return -1; } /* Check that the sig is of the correct size. */ len = GET_ISAKMP_GEN_LENGTH (p->p) - ISAKMP_SIG_SZ; if (len != RSA_size (key)) { RSA_free (key); log_print ("rsa_sig_decode_hash: " "SIG payload length does not match public key"); return -1; } *hash_p = malloc (len); if (!*hash_p) { RSA_free (key); log_error ("rsa_sig_decode_hash: malloc (%d) failed", len); return -1; } len = RSA_public_decrypt (len, p->p + ISAKMP_SIG_DATA_OFF, *hash_p, key, RSA_PKCS1_PADDING); if (len == -1) { RSA_free (key); log_print ("rsa_sig_decode_hash: RSA_public_decrypt () failed"); return -1; } /* Store key for later use */ exchange->recv_key = key; exchange->recv_keytype = ISAKMP_KEY_RSA; if (len != hashsize) { free (*hash_p); *hash_p = 0; log_print ("rsa_sig_decode_hash: len %lu != hashsize %lu", (unsigned long)len, (unsigned long)hashsize); return -1; } snprintf (header, sizeof header, "rsa_sig_decode_hash: HASH_%c", initiator ? 'R' : 'I'); LOG_DBG_BUF ((LOG_MISC, 80, header, *hash_p, hashsize)); p->flags |= PL_MARK; return 0; }
/* Encrypt the HASH into a SIG type. */ static int rsa_sig_encode_hash (struct message *msg) { struct exchange *exchange = msg->exchange; struct ipsec_exch *ie = exchange->data; size_t hashsize = ie->hash->hashsize; struct cert_handler *handler; char header[80]; int initiator = exchange->initiator; u_int8_t *buf, *data, *buf2; u_int32_t datalen; u_int8_t *id; size_t id_len; int idtype; void *sent_key; id = initiator ? exchange->id_i : exchange->id_r; id_len = initiator ? exchange->id_i_len : exchange->id_r_len; /* We may have been provided these by the kernel */ buf = (u_int8_t *)conf_get_str (exchange->name, "Credentials"); if (buf && (idtype = conf_get_num (exchange->name, "Credential_Type", -1) != -1)) { exchange->sent_certtype = idtype; handler = cert_get (idtype); if (!handler) { log_print ("rsa_sig_encode_hash: cert_get (%d) failed", idtype); return -1; } exchange->sent_cert = handler->cert_from_printable ((char *)buf); if (!exchange->sent_cert) { log_print ("rsa_sig_encode_hash: failed to retrieve certificate"); return -1; } handler->cert_serialize (exchange->sent_cert, &data, &datalen); if (!data) { log_print ("rsa_sig_encode_hash: cert serialization failed"); return -1; } goto aftercert; /* Skip all the certificate discovery */ } /* XXX This needs to be configurable. */ idtype = ISAKMP_CERTENC_KEYNOTE; /* Find a certificate with subjectAltName = id. */ handler = cert_get (idtype); if (!handler) { idtype = ISAKMP_CERTENC_X509_SIG; handler = cert_get (idtype); if (!handler) { log_print ("rsa_sig_encode_hash: cert_get(%d) failed", idtype); return -1; } } if (handler->cert_obtain (id, id_len, 0, &data, &datalen) == 0) { if (idtype == ISAKMP_CERTENC_KEYNOTE) { idtype = ISAKMP_CERTENC_X509_SIG; handler = cert_get (idtype); if (!handler) { log_print ("rsa_sig_encode_hash: cert_get(%d) failed", idtype); return -1; } if (handler->cert_obtain (id, id_len, 0, &data, &datalen) == 0) { LOG_DBG ((LOG_MISC, 10, "rsa_sig_encode_hash: no certificate to send")); goto skipcert; } } else { LOG_DBG ((LOG_MISC, 10, "rsa_sig_encode_hash: no certificate to send")); goto skipcert; } } /* Let's store the certificate we are going to use */ exchange->sent_certtype = idtype; exchange->sent_cert = handler->cert_get (data, datalen); if (!exchange->sent_cert) { free (data); log_print ("rsa_sig_encode_hash: failed to get certificate from wire " "encoding"); return -1; } aftercert: buf = realloc (data, ISAKMP_CERT_SZ + datalen); if (!buf) { log_error ("rsa_sig_encode_hash: realloc (%p, %d) failed", data, ISAKMP_CERT_SZ + datalen); free (data); return -1; } memmove (buf + ISAKMP_CERT_SZ, buf, datalen); SET_ISAKMP_CERT_ENCODING (buf, idtype); if (message_add_payload (msg, ISAKMP_PAYLOAD_CERT, buf, ISAKMP_CERT_SZ + datalen, 1)) { free (buf); return -1; } skipcert: /* Again, we may have these from the kernel */ buf = (u_int8_t *)conf_get_str (exchange->name, "PKAuthentication"); if (buf) { key_from_printable (ISAKMP_KEY_RSA, ISAKMP_KEYTYPE_PRIVATE, (char *)buf, &data, &datalen); if (!data || datalen == -1) { log_print ("rsa_sig_encode_hash: badly formatted RSA private key"); return 0; } sent_key = key_internalize (ISAKMP_KEY_RSA, ISAKMP_KEYTYPE_PRIVATE, data, datalen); if (!sent_key) { log_print ("rsa_sig_encode_hash: bad RSA private key from dynamic " "SA acquisition subsystem"); return 0; } #if defined (USE_PRIVSEP) { /* With USE_PRIVSEP, the sent_key should be a key number. */ void *key = sent_key; sent_key = monitor_RSA_upload_key (key); } #endif } else /* Try through the regular means. */ { switch (id[ISAKMP_ID_TYPE_OFF - ISAKMP_GEN_SZ]) { case IPSEC_ID_IPV4_ADDR: case IPSEC_ID_IPV6_ADDR: util_ntoa ((char **)&buf2, id[ISAKMP_ID_TYPE_OFF - ISAKMP_GEN_SZ] == IPSEC_ID_IPV4_ADDR ? AF_INET : AF_INET6, id + ISAKMP_ID_DATA_OFF - ISAKMP_GEN_SZ); if (!buf2) return 0; break; case IPSEC_ID_FQDN: case IPSEC_ID_USER_FQDN: buf2 = calloc (id_len - ISAKMP_ID_DATA_OFF + ISAKMP_GEN_SZ + 1, sizeof (char)); if (!buf2) { log_print ("rsa_sig_encode_hash: malloc (%lu) failed", (unsigned long)id_len - ISAKMP_ID_DATA_OFF + ISAKMP_GEN_SZ + 1); return 0; } memcpy (buf2, id + ISAKMP_ID_DATA_OFF - ISAKMP_GEN_SZ, id_len - ISAKMP_ID_DATA_OFF + ISAKMP_GEN_SZ); break; /* XXX Support more ID types? */ default: buf2 = 0; return 0; } #if defined (USE_PRIVSEP) sent_key = monitor_RSA_get_private_key (exchange->name, (char *)buf2); #else sent_key = ike_auth_get_key (IKE_AUTH_RSA_SIG, exchange->name, (char *)buf2, 0); #endif free (buf2); /* Did we find a key? */ if (!sent_key) { log_print ("rsa_sig_encode_hash: could not get private key"); return -1; } } #if !defined (USE_PRIVSEP) /* Enable RSA blinding. */ if (RSA_blinding_on (sent_key, NULL) != 1) { log_error ("rsa_sig_encode_hash: RSA_blinding_on () failed."); return -1; } #endif /* XXX hashsize is not necessarily prf->blocksize. */ buf = malloc (hashsize); if (!buf) { log_error ("rsa_sig_encode_hash: malloc (%lu) failed", (unsigned long)hashsize); return -1; } if (ike_auth_hash (exchange, buf) == -1) { free (buf); return -1; } snprintf (header, sizeof header, "rsa_sig_encode_hash: HASH_%c", initiator ? 'I' : 'R'); LOG_DBG_BUF ((LOG_MISC, 80, header, buf, hashsize)); #if !defined (USE_PRIVSEP) data = malloc (RSA_size (sent_key)); if (!data) { log_error ("rsa_sig_encode_hash: malloc (%d) failed", RSA_size (sent_key)); return -1; } datalen = RSA_private_encrypt (hashsize, buf, data, sent_key, RSA_PKCS1_PADDING); #else datalen = monitor_RSA_private_encrypt (hashsize, buf, &data, sent_key, RSA_PKCS1_PADDING); #endif /* USE_PRIVSEP */ if (datalen == -1) { log_print ("rsa_sig_encode_hash: RSA_private_encrypt () failed"); if (data) free (data); free (buf); monitor_RSA_free (sent_key); return -1; } free (buf); buf = realloc (data, ISAKMP_SIG_SZ + datalen); if (!buf) { log_error ("rsa_sig_encode_hash: realloc (%p, %d) failed", data, ISAKMP_SIG_SZ + datalen); free (data); return -1; } memmove (buf + ISAKMP_SIG_SZ, buf, datalen); snprintf (header, sizeof header, "rsa_sig_encode_hash: SIG_%c", initiator ? 'I' : 'R'); LOG_DBG_BUF ((LOG_MISC, 80, header, buf + ISAKMP_SIG_DATA_OFF, datalen)); if (message_add_payload (msg, ISAKMP_PAYLOAD_SIG, buf, ISAKMP_SIG_SZ + datalen, 1)) { free (buf); return -1; } return 0; }
int ike_phase_1_send_ID (struct message *msg) { struct exchange *exchange = msg->exchange; u_int8_t *buf; char header[80]; ssize_t sz; struct sockaddr *src; int initiator = exchange->initiator; u_int8_t **id; size_t *id_len; char *my_id = 0; u_int8_t id_type; /* Choose the right fields to fill-in. */ id = initiator ? &exchange->id_i : &exchange->id_r; id_len = initiator ? &exchange->id_i_len : &exchange->id_r_len; if (exchange->name) my_id = conf_get_str (exchange->name, "ID"); if (!my_id) my_id = conf_get_str ("General", "Default-phase-1-ID"); msg->transport->vtbl->get_src (msg->transport, &src); sz = my_id ? ipsec_id_size (my_id, &id_type) : sockaddr_addrlen (src); if (sz == -1) return -1; sz += ISAKMP_ID_DATA_OFF; buf = malloc (sz); if (!buf) { log_error ("ike_phase_1_send_ID: malloc (%lu) failed", (unsigned long)sz); return -1; } SET_IPSEC_ID_PROTO (buf + ISAKMP_ID_DOI_DATA_OFF, 0); SET_IPSEC_ID_PORT (buf + ISAKMP_ID_DOI_DATA_OFF, 0); if (my_id) { SET_ISAKMP_ID_TYPE (buf, id_type); switch (id_type) { case IPSEC_ID_IPV4_ADDR: case IPSEC_ID_IPV6_ADDR: /* Already in network byteorder. */ memcpy (buf + ISAKMP_ID_DATA_OFF, sockaddr_addrdata (src), sockaddr_addrlen (src)); break; case IPSEC_ID_FQDN: case IPSEC_ID_USER_FQDN: case IPSEC_ID_KEY_ID: memcpy (buf + ISAKMP_ID_DATA_OFF, conf_get_str (my_id, "Name"), sz - ISAKMP_ID_DATA_OFF); break; default: log_print ("ike_phase_1_send_ID: unsupported ID type %d", id_type); free (buf); return -1; } } else { switch (src->sa_family) { case AF_INET: SET_ISAKMP_ID_TYPE (buf, IPSEC_ID_IPV4_ADDR); break; case AF_INET6: SET_ISAKMP_ID_TYPE (buf, IPSEC_ID_IPV6_ADDR); break; } /* Already in network byteorder. */ memcpy (buf + ISAKMP_ID_DATA_OFF, sockaddr_addrdata (src), sockaddr_addrlen (src)); } if (message_add_payload (msg, ISAKMP_PAYLOAD_ID, buf, sz, 1)) { free (buf); return -1; } *id_len = sz - ISAKMP_GEN_SZ; *id = malloc (*id_len); if (!*id) { log_error ("ike_phase_1_send_ID: malloc (%lu) failed", (unsigned long)*id_len); return -1; } memcpy (*id, buf + ISAKMP_GEN_SZ, *id_len); snprintf (header, sizeof header, "ike_phase_1_send_ID: %s", constant_name (ipsec_id_cst, GET_ISAKMP_ID_TYPE (buf))); LOG_DBG_BUF ((LOG_NEGOTIATION, 40, header, buf + ISAKMP_ID_DATA_OFF, sz - ISAKMP_ID_DATA_OFF)); return 0; }
/* * Compute DH values and key material. This is done in a post-send function * as that means we can do parallel work in both the initiator and responder * thus speeding up exchanges. */ int ike_phase_1_post_exchange_KE_NONCE (struct message *msg) { struct exchange *exchange = msg->exchange; struct ipsec_exch *ie = exchange->data; struct prf *prf; struct hash *hash = ie->hash; enum cryptoerr err; /* Compute Diffie-Hellman shared value. */ ie->g_xy = malloc (ie->g_x_len); if (!ie->g_xy) { /* XXX How to notify peer? */ log_error ("ike_phase_1_post_exchange_KE_NONCE: malloc (%lu) failed", (unsigned long)ie->g_x_len); return -1; } if (dh_create_shared (ie->group, ie->g_xy, exchange->initiator ? ie->g_xr : ie->g_xi)) { log_print ("ike_phase_1_post_exchange_KE_NONCE: " "dh_create_shared failed"); return -1; } LOG_DBG_BUF ((LOG_NEGOTIATION, 80, "ike_phase_1_post_exchange_KE_NONCE: g^xy", ie->g_xy, ie->g_x_len)); /* Compute the SKEYID depending on the authentication method. */ ie->skeyid = ie->ike_auth->gen_skeyid (exchange, &ie->skeyid_len); if (!ie->skeyid) { /* XXX Log and teardown? */ return -1; } LOG_DBG_BUF ((LOG_NEGOTIATION, 80, "ike_phase_1_post_exchange_KE_NONCE: SKEYID", ie->skeyid, ie->skeyid_len)); /* SKEYID_d. */ ie->skeyid_d = malloc (ie->skeyid_len); if (!ie->skeyid_d) { /* XXX How to notify peer? */ log_error ("ike_phase_1_post_exchange_KE_NONCE: malloc (%lu) failed", (unsigned long)ie->skeyid_len); return -1; } prf = prf_alloc (ie->prf_type, hash->type, ie->skeyid, ie->skeyid_len); if (!prf) { /* XXX Log and teardown? */ return -1; } prf->Init (prf->prfctx); prf->Update (prf->prfctx, ie->g_xy, ie->g_x_len); prf->Update (prf->prfctx, exchange->cookies, ISAKMP_HDR_COOKIES_LEN); prf->Update (prf->prfctx, (unsigned char *)"\0", 1); prf->Final (ie->skeyid_d, prf->prfctx); LOG_DBG_BUF ((LOG_NEGOTIATION, 80, "ike_phase_1_post_exchange_KE_NONCE: SKEYID_d", ie->skeyid_d, ie->skeyid_len)); /* SKEYID_a. */ ie->skeyid_a = malloc (ie->skeyid_len); if (!ie->skeyid_a) { log_error ("ike_phase_1_post_exchange_KE_NONCE: malloc (%lu) failed", (unsigned long)ie->skeyid_len); prf_free (prf); return -1; } prf->Init (prf->prfctx); prf->Update (prf->prfctx, ie->skeyid_d, ie->skeyid_len); prf->Update (prf->prfctx, ie->g_xy, ie->g_x_len); prf->Update (prf->prfctx, exchange->cookies, ISAKMP_HDR_COOKIES_LEN); prf->Update (prf->prfctx, (unsigned char *)"\1", 1); prf->Final (ie->skeyid_a, prf->prfctx); LOG_DBG_BUF ((LOG_NEGOTIATION, 80, "ike_phase_1_post_exchange_KE_NONCE: SKEYID_a", ie->skeyid_a, ie->skeyid_len)); /* SKEYID_e. */ ie->skeyid_e = malloc (ie->skeyid_len); if (!ie->skeyid_e) { /* XXX How to notify peer? */ log_error ("ike_phase_1_post_exchange_KE_NONCE: malloc (%lu) failed", (unsigned long)ie->skeyid_len); prf_free (prf); return -1; } prf->Init (prf->prfctx); prf->Update (prf->prfctx, ie->skeyid_a, ie->skeyid_len); prf->Update (prf->prfctx, ie->g_xy, ie->g_x_len); prf->Update (prf->prfctx, exchange->cookies, ISAKMP_HDR_COOKIES_LEN); prf->Update (prf->prfctx, (unsigned char *)"\2", 1); prf->Final (ie->skeyid_e, prf->prfctx); prf_free (prf); LOG_DBG_BUF ((LOG_NEGOTIATION, 80, "ike_phase_1_post_exchange_KE_NONCE: SKEYID_e", ie->skeyid_e, ie->skeyid_len)); /* Key length determination. */ if (!exchange->key_length) exchange->key_length = exchange->crypto->keymax; /* Derive a longer key from skeyid_e */ if (ie->skeyid_len < exchange->key_length) { u_int16_t len, keylen; u_int8_t *key, *p; prf = prf_alloc (ie->prf_type, hash->type, ie->skeyid_e, ie->skeyid_len); if (!prf) { /* XXX - notify peer */ return -1; } /* Make keylen a multiple of prf->blocksize */ keylen = exchange->key_length; if (keylen % prf->blocksize) keylen += prf->blocksize - (keylen % prf->blocksize); key = malloc (keylen); if (!key) { /* XXX - Notify peer. */ log_error ("ike_phase_1_post_exchange_KE_NONCE: malloc (%d) failed", keylen); return -1; } prf->Init (prf->prfctx); prf->Update (prf->prfctx, (unsigned char *)"\0", 1); prf->Final (key, prf->prfctx); for (len = prf->blocksize, p = key; len < exchange->key_length; len += prf->blocksize, p += prf->blocksize) { prf->Init (prf->prfctx); prf->Update (prf->prfctx, p, prf->blocksize); prf->Final (p + prf->blocksize, prf->prfctx); } prf_free (prf); /* Setup our keystate using the derived encryption key. */ exchange->keystate = crypto_init (exchange->crypto, key, exchange->key_length, &err); free (key); } else /* Setup our keystate using the raw skeyid_e. */ exchange->keystate = crypto_init (exchange->crypto, ie->skeyid_e, exchange->key_length, &err); /* Special handling for DES weak keys. */ if (!exchange->keystate && err == EWEAKKEY && (exchange->key_length << 1) <= ie->skeyid_len) { log_print ("ike_phase_1_post_exchange_KE_NONCE: " "weak key, trying subseq. skeyid_e"); exchange->keystate = crypto_init (exchange->crypto, ie->skeyid_e + exchange->key_length, exchange->key_length, &err); } if (!exchange->keystate) { log_print ("ike_phase_1_post_exchange_KE_NONCE: " "exchange->crypto->init () failed: %d", err); /* * XXX We really need to know if problems are of transient nature * or fatal (like failed assertions etc.) */ return -1; } /* Setup IV. XXX Only for CBC transforms, no? */ hash->Init (hash->ctx); hash->Update (hash->ctx, ie->g_xi, ie->g_x_len); hash->Update (hash->ctx, ie->g_xr, ie->g_x_len); hash->Final (hash->digest, hash->ctx); crypto_init_iv (exchange->keystate, hash->digest, exchange->crypto->blocksize); return 0; }