static int isakmp_responder(struct message *msg) { struct payload *p; u_int16_t type; switch (msg->exchange->type) { case ISAKMP_EXCH_INFO: for (p = payload_first(msg, ISAKMP_PAYLOAD_NOTIFY); p; p = TAILQ_NEXT(p, link)) { type = GET_ISAKMP_NOTIFY_MSG_TYPE(p->p); LOG_DBG((LOG_EXCHANGE, 10, "isakmp_responder: " "got NOTIFY of type %s", constant_name(isakmp_notify_cst, type))); switch (type) { case ISAKMP_NOTIFY_STATUS_DPD_R_U_THERE: case ISAKMP_NOTIFY_STATUS_DPD_R_U_THERE_ACK: dpd_handle_notify(msg, p); break; default: p->flags |= PL_MARK; break; } } for (p = payload_first(msg, ISAKMP_PAYLOAD_DELETE); p; p = TAILQ_NEXT(p, link)) { LOG_DBG((LOG_EXCHANGE, 10, "isakmp_responder: got DELETE, ignoring")); p->flags |= PL_MARK; } return 0; case ISAKMP_EXCH_TRANSACTION: /* return 0 isakmp_cfg_responder (msg); */ default: /* XXX So far we don't accept any proposals. */ if (payload_first(msg, ISAKMP_PAYLOAD_SA)) { message_drop(msg, ISAKMP_NOTIFY_NO_PROPOSAL_CHOSEN, 0, 1, 0); return -1; } } return 0; }
/* * As "the server", this starts REQ/REPLY (initiated by the client). * As "the client", this starts SET/ACK (initiated by the server). */ static int cfg_responder_recv_ATTR(struct message *msg) { struct payload *attrp = payload_first(msg, ISAKMP_PAYLOAD_ATTRIBUTE); struct ipsec_exch *ie = msg->exchange->data; struct sa *isakmp_sa = msg->isakmp_sa; struct isakmp_cfg_attr *attr; struct sockaddr *sa; char *addr; if (msg->exchange->phase == 2) if (cfg_verify_hash(msg)) return -1; ie->cfg_id = GET_ISAKMP_ATTRIBUTE_ID(attrp->p); ie->cfg_type = attrp->p[ISAKMP_ATTRIBUTE_TYPE_OFF]; switch (ie->cfg_type) { case ISAKMP_CFG_REQUEST: case ISAKMP_CFG_SET: break; default: message_drop(msg, ISAKMP_NOTIFY_PAYLOAD_MALFORMED, 0, 1, 0); log_print("cfg_responder_recv_ATTR: " "unexpected configuration message type %d", ie->cfg_type); return -1; } attribute_map(attrp->p + ISAKMP_ATTRIBUTE_ATTRS_OFF, GET_ISAKMP_GEN_LENGTH(attrp->p) - ISAKMP_TRANSFORM_SA_ATTRS_OFF, cfg_decode_attribute, ie); switch (ie->cfg_type) { case ISAKMP_CFG_REQUEST: /* We're done. */ break; case ISAKMP_CFG_SET: { /* SET/ACK -- Client side (SET from server) */ const char *uk_addr = "<unknown>"; msg->transport->vtbl->get_dst(isakmp_sa->transport, &sa); if (sockaddr2text(sa, &addr, 0) < 0) addr = (char *) uk_addr; for (attr = LIST_FIRST(&ie->attrs); attr; attr = LIST_NEXT(attr, link)) LOG_DBG((LOG_NEGOTIATION, 50, "cfg_responder_recv_ATTR: " "server %s asks us to SET attribute %s", addr, constant_name(isakmp_cfg_attr_cst, attr->type))); /* * XXX Here's the place to add code to walk through * XXX each attribute and send them along to dhclient * XXX or whatever. Each attribute that we act upon * XXX (such as setting a netmask), should be marked * XXX like this for us to send the proper ACK * XXX response: attr->attr_used++; */ if (addr != uk_addr) free(addr); } break; default: break; } attrp->flags |= PL_MARK; return 0; }
/* * As "the server", this ends SET/ACK. * As "the client", this ends REQ/REPLY. */ static int cfg_initiator_recv_ATTR(struct message *msg) { struct payload *attrp = payload_first(msg, ISAKMP_PAYLOAD_ATTRIBUTE); struct ipsec_exch *ie = msg->exchange->data; struct sa *isakmp_sa = msg->isakmp_sa; struct isakmp_cfg_attr *attr; struct sockaddr *sa; const char *uk_addr = "<unknown>"; char *addr; if (msg->exchange->phase == 2) if (cfg_verify_hash(msg)) return -1; /* Sanity. */ if (ie->cfg_id != GET_ISAKMP_ATTRIBUTE_ID(attrp->p)) { log_print("cfg_initiator_recv_ATTR: " "cfg packet ID does not match!"); message_drop(msg, ISAKMP_NOTIFY_PAYLOAD_MALFORMED, 0, 1, 0); return -1; } switch (attrp->p[ISAKMP_ATTRIBUTE_TYPE_OFF]) { case ISAKMP_CFG_ACK: if (ie->cfg_type != ISAKMP_CFG_SET) { log_print("cfg_initiator_recv_ATTR: " "bad packet type ACK"); message_drop(msg, ISAKMP_NOTIFY_PAYLOAD_MALFORMED, 0, 1, 0); return -1; } break; case ISAKMP_CFG_REPLY: if (ie->cfg_type != ISAKMP_CFG_REQUEST) { log_print("cfg_initiator_recv_ATTR: " "bad packet type REPLY"); message_drop(msg, ISAKMP_NOTIFY_PAYLOAD_MALFORMED, 0, 1, 0); return -1; } break; default: log_print("cfg_initiator_recv_ATTR: unexpected configuration " "message type %d", attrp->p[ISAKMP_ATTRIBUTE_TYPE_OFF]); message_drop(msg, ISAKMP_NOTIFY_PAYLOAD_MALFORMED, 0, 1, 0); return -1; } attribute_map(attrp->p + ISAKMP_ATTRIBUTE_ATTRS_OFF, GET_ISAKMP_GEN_LENGTH(attrp->p) - ISAKMP_TRANSFORM_SA_ATTRS_OFF, cfg_decode_attribute, ie); switch (ie->cfg_type) { case ISAKMP_CFG_ACK: { /* SET/ACK -- Server side (ACK from client) */ msg->transport->vtbl->get_src(isakmp_sa->transport, &sa); if (sockaddr2text(sa, &addr, 0) < 0) addr = (char *) uk_addr; for (attr = LIST_FIRST(&ie->attrs); attr; attr = LIST_NEXT(attr, link)) LOG_DBG((LOG_NEGOTIATION, 50, "cfg_initiator_recv_ATTR: " "client %s ACKs attribute %s", addr, constant_name(isakmp_cfg_attr_cst, attr->type))); if (addr != uk_addr) free(addr); } break; case ISAKMP_CFG_REPLY: { /* * REQ/REPLY: effect attributes we've gotten * responses on. */ msg->transport->vtbl->get_src(isakmp_sa->transport, &sa); if (sockaddr2text(sa, &addr, 0) < 0) addr = (char *) uk_addr; for (attr = LIST_FIRST(&ie->attrs); attr; attr = LIST_NEXT(attr, link)) LOG_DBG((LOG_NEGOTIATION, 50, "cfg_initiator_recv_ATTR: " "server %s replied with attribute %s", addr, constant_name(isakmp_cfg_attr_cst, attr->type))); if (addr != uk_addr) free(addr); } break; default: break; } attrp->flags |= PL_MARK; return 0; }
/* 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; }
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; }
/* * Look at the attribute of type TYPE, located at VALUE for LEN bytes forward. * The VVS argument holds a validation state kept across invocations. * If the attribute is unacceptable to use, return non-zero, otherwise zero. */ static int attribute_unacceptable (u_int16_t type, u_int8_t *value, u_int16_t len, void *vvs) { struct validation_state *vs = vvs; struct conf_list *life_conf; struct conf_list_node *xf = vs->xf, *life; char *tag = constant_lookup (ike_attr_cst, type); char *str; struct constant_map *map; struct attr_node *node; int rv; if (!tag) { LOG_DBG ((LOG_NEGOTIATION, 60, "attribute_unacceptable: attribute type %d not known", type)); return 1; } switch (type) { case IKE_ATTR_ENCRYPTION_ALGORITHM: case IKE_ATTR_HASH_ALGORITHM: case IKE_ATTR_AUTHENTICATION_METHOD: case IKE_ATTR_GROUP_DESCRIPTION: case IKE_ATTR_GROUP_TYPE: case IKE_ATTR_PRF: str = conf_get_str (xf->field, tag); if (!str) { /* This attribute does not exist in this policy. */ LOG_DBG ((LOG_NEGOTIATION, 70, "attribute_unacceptable: attr %s does not exist in %s", tag, xf->field)); return 1; } map = constant_link_lookup (ike_attr_cst, type); if (!map) return 1; if ((constant_value (map, str) == decode_16 (value)) || (!strcmp (str, "ANY"))) { /* Mark this attribute as seen. */ node = malloc (sizeof *node); if (!node) { log_error ("attribute_unacceptable: malloc (%lu) failed", (unsigned long)sizeof *node); return 1; } node->type = type; LIST_INSERT_HEAD (&vs->attrs, node, link); return 0; } LOG_DBG ((LOG_NEGOTIATION, 30, "attribute_unacceptable: %s: got '%s', expected '%s'", tag, constant_name (map, decode_16 (value)), str)); return 1; case IKE_ATTR_GROUP_PRIME: case IKE_ATTR_GROUP_GENERATOR_1: case IKE_ATTR_GROUP_GENERATOR_2: case IKE_ATTR_GROUP_CURVE_A: case IKE_ATTR_GROUP_CURVE_B: /* XXX Bignums not handled yet. */ return 1; case IKE_ATTR_LIFE_TYPE: case IKE_ATTR_LIFE_DURATION: life_conf = conf_get_list (xf->field, "Life"); if (life_conf && !strcmp (conf_get_str (xf->field, "Life"), "ANY")) return 0; rv = 1; if (!life_conf) { /* Life attributes given, but not in our policy. */ LOG_DBG ((LOG_NEGOTIATION, 70, "attribute_unacceptable: " "received unexpected life attribute")); return 1; } /* * Each lifetime type must match, otherwise we turn the proposal down. * In order to do this we need to find the specific section of our * policy's "Life" list and match its duration */ switch (type) { case IKE_ATTR_LIFE_TYPE: for (life = TAILQ_FIRST (&life_conf->fields); life; life = TAILQ_NEXT (life, link)) { str = conf_get_str (life->field, "LIFE_TYPE"); if (!str) { LOG_DBG ((LOG_NEGOTIATION, 70, "attribute_unacceptable: " "section [%s] has no LIFE_TYPE", life->field)); continue; } /* * If this is the type we are looking at, save a pointer * to this section in vs->life. */ if (constant_value (ike_duration_cst, str) == decode_16 (value)) { vs->life = strdup (life->field); rv = 0; goto bail_out; } } LOG_DBG ((LOG_NEGOTIATION, 70, "attribute_unacceptable: unrecognized LIFE_TYPE %d", decode_16 (value))); vs->life = 0; break; case IKE_ATTR_LIFE_DURATION: if (!vs->life) { LOG_DBG ((LOG_NEGOTIATION, 70, "attribute_unacceptable: " "LIFE_DURATION without LIFE_TYPE")); rv = 1; goto bail_out; } str = conf_get_str (vs->life, "LIFE_DURATION"); if (str) { if (!strcmp (str, "ANY")) rv = 0; else rv = !conf_match_num (vs->life, "LIFE_DURATION", len == 4 ? decode_32 (value) : decode_16 (value)); } else { LOG_DBG ((LOG_NEGOTIATION, 70, "attribute_unacceptable: " "section [%s] has no LIFE_DURATION", vs->life)); rv = 1; } free (vs->life); vs->life = 0; break; } bail_out: conf_free_list (life_conf); return rv; case IKE_ATTR_KEY_LENGTH: case IKE_ATTR_FIELD_SIZE: case IKE_ATTR_GROUP_ORDER: if (conf_match_num (xf->field, tag, decode_16 (value))) { /* Mark this attribute as seen. */ node = malloc (sizeof *node); if (!node) { log_error ("attribute_unacceptable: malloc (%lu) failed", (unsigned long)sizeof *node); return 1; } node->type = type; LIST_INSERT_HEAD (&vs->attrs, node, link); return 0; } return 1; } return 1; }
/* 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; }