/* * Check the vendor ID payload -- return the vendor ID index * if we find a recognized one, or UNKNOWN if we don't. * * gen ... points to Vendor ID payload. */ int check_vendorid(struct isakmp_gen *gen) { vchar_t vid, *vidhash; int i, vidlen; struct vendor_id *current; if (gen == NULL) return (VENDORID_UNKNOWN); vidlen = ntohs(gen->len) - sizeof(*gen); current = lookup_vendor_id_by_hash((char *)(gen + 1)); if (!current) goto unknown; if (current->hash->l < vidlen) plog(LLV_INFO, LOCATION, NULL, "received broken Microsoft ID: %s\n", current->string); else plog(LLV_INFO, LOCATION, NULL, "received Vendor ID: %s\n", current->string); return current->id; unknown: plog(LLV_DEBUG, LOCATION, NULL, "received unknown Vendor ID\n"); plogdump(LLV_DEBUG, (char *)(gen + 1), vidlen); return (VENDORID_UNKNOWN); }
/* * generate octet string for auth calculation input */ static rc_vchar_t * ikev2_auth_input(struct ikev2_sa *sa, int i_to_r) { rc_vchar_t *message; rc_vchar_t *octets = 0; rc_vchar_t *nonce; rc_vchar_t *sk; rc_vchar_t *id; struct keyed_hash *prf = sa->prf; uint8_t *p; rc_vchar_t *prf_output = 0; TRACE((PLOGLOC, "ikev2_auth_input(%p, %d)\n", sa, i_to_r)); /* (draft-17) * For the responder, the octets to * be signed start with the first octet of the first SPI in the header * of the second message and end with the last octet of the last payload * in the second message. Appended to this (for purposes of computing * the signature) are the initiator's nonce Ni (just the value, not the * payload containing it), and the value prf(SK_pr,IDr') where IDr' is * the responder's ID payload excluding the fixed header. */ /* sign(packet | Ni | prf(SK_pr, IDr')) */ /* * the initiator signs the first message, starting with the * first octet of the first SPI in the header and ending with the last * octet of the last payload. Appended to this (for purposes of * computing the signature) are the responder's nonce Nr, and the value * prf(SK_pi,IDi'). In the above calculation, IDi' and IDr' are the * entire ID payloads excluding the fixed header. */ /* sign(packet | Nr | prf(SK_pi, IDi')) */ /* * Optionally, messages 3 and 4 MAY include a certificate, or * certificate chain providing evidence that the key used to compute a * digital signature belongs to the name in the ID payload. The * signature or MAC will be computed using algorithms dictated by the * type of key used by the signer, and specified by the Auth Method * field in the Authentication payload. */ /* * In the case of a pre-shared key, the AUTH * value is computed as: * * AUTH = prf(prf(Shared Secret,"Key Pad for IKEv2"), <msg octets>) */ #ifdef notyet /* * For EAP methods that create a shared key as a side effect of * authentication, that shared key MUST be used by both the initiator * and responder to generate AUTH payloads in messages 5 and 6 using the * syntax for shared secrets specified in section 2.15. The shared key * from EAP is the field from the EAP specification named MSK. The * shared key generated during an IKE exchange MUST NOT be used for any * other purpose. * * EAP methods that do not establish a shared key SHOULD NOT be used, as * they are subject to a number of man-in-the-middle attacks [EAPMITM] * if these EAP methods are used in other protocols that do not use a * server-authenticated tunnel. Please see the Security Considerations * section for more details. If EAP methods that do not generate a * shared key are used, the AUTH payloads in messages 7 and 8 MUST be * generated using SK_pi and SK_pr respectively. */ #endif /* (draft-eronen-ipsec-ikev2-clarifications-05.txt) * 3.1 Data included in AUTH payload calculation * * Section 2.15 describes how the AUTH payloads are calculated; this * calculation involves values prf(SK_pi,IDi') and prf(SK_pr,IDr'). The * text describes the method in words, but does not give clear * definitions of what is signed or MACed. * * The initiator's signed octets can be described as: * * InitiatorSignedOctets = RealMessage1 | NonceRData | MACedIDForI * GenIKEHDR = [ four octets 0 if using port 4500 ] | RealIKEHDR * RealIKEHDR = SPIi | SPIr | . . . | Length * RealMessage1 = RealIKEHDR | RestOfMessage1 * NonceRPayload = PayloadHeader | NonceRData * InitiatorIDPayload = PayloadHeader | RestOfIDPayload * RestOfInitIDPayload = IDType | RESERVED | InitIDData * MACedIDForI = prf(SK_pi, RestOfInitIDPayload) * * The responder's signed octets can be described as: * * ResponderSignedOctets = RealMessage2 | NonceIData | MACedIDForR * GenIKEHDR = [ four octets 0 if using port 4500 ] | RealIKEHDR * RealIKEHDR = SPIi | SPIr | . . . | Length * RealMessage2 = RealIKEHDR | RestOfMessage2 * NonceIPayload = PayloadHeader | NonceIData * ResponderIDPayload = PayloadHeader | RestOfIDPayload * RestOfRespIDPayload = IDType | RESERVED | InitIDData * MACedIDForR = prf(SK_pr, RestOfRespIDPayload) */ if (sa->is_initiator ? i_to_r : (!i_to_r)) { assert(sa->my_first_message); message = sa->my_first_message; } else { assert(sa->peer_first_message); message = sa->peer_first_message; } if (i_to_r) { nonce = sa->n_r; sk = sa->sk_p_i; id = sa->id_i; } else { nonce = sa->n_i; sk = sa->sk_p_r; id = sa->id_r; } IF_TRACE({ TRACE((PLOGLOC, "SK\n")); plogdump(PLOG_DEBUG, PLOGLOC, 0, sk->v, sk->l); TRACE((PLOGLOC, "ID\n")); plogdump(PLOG_DEBUG, PLOGLOC, 0, id->v, id->l); });
/* send packet, with fixing src/dst address pair. */ int sendfromto(int s, const void *buf, size_t buflen, struct sockaddr *src, struct sockaddr *dst, int cnt) { struct sockaddr_storage ss; socklen_t sslen; int len = 0, i; extern struct rcf_interface *rcf_interface_head; if (cnt <= 0) { TRACE((PLOGLOC, "cnt: %d\n", cnt)); return 0; } if (src->sa_family != dst->sa_family) { plog(PLOG_INTERR, PLOGLOC, NULL, "address family mismatch\n"); return -1; } memset(&ss, 0, sizeof(ss)); sslen = sizeof(ss); if (getsockname(s, (struct sockaddr *)&ss, &sslen) < 0) { plog(PLOG_INTERR, PLOGLOC, NULL, "getsockname (%s)\n", strerror(errno)); return -1; } plog(PLOG_DEBUG, PLOGLOC, NULL, "sockname %s\n", rcs_sa2str((struct sockaddr *)&ss)); plog(PLOG_DEBUG, PLOGLOC, NULL, "send packet from %s\n", rcs_sa2str(src)); plog(PLOG_DEBUG, PLOGLOC, NULL, "send packet to %s\n", rcs_sa2str(dst)); if (src->sa_family != SOCKADDR_FAMILY(&ss)) { plog(PLOG_INTERR, PLOGLOC, NULL, "address family mismatch\n"); return -1; } switch (src->sa_family) { #if defined(INET6) && defined(ADVAPI) && !defined(IPV6_INRIA_VERSION) case AF_INET6: { struct msghdr m; struct cmsghdr *cm; struct iovec iov[2]; unsigned char cmsgbuf[256]; struct in6_pktinfo *pi; int ifindex; struct sockaddr_in6 src6, dst6; memcpy(&src6, src, sizeof(src6)); memcpy(&dst6, dst, sizeof(dst6)); /* XXX take care of other cases, such as site-local */ ifindex = 0; if (IN6_IS_ADDR_LINKLOCAL(&src6.sin6_addr) || IN6_IS_ADDR_MULTICAST(&src6.sin6_addr)) { ifindex = src6.sin6_scope_id; /*??? */ } /* XXX some sanity check on dst6.sin6_scope_id */ /* flowinfo for IKE? mmm, maybe useful but for now make it 0 */ src6.sin6_flowinfo = dst6.sin6_flowinfo = 0; memset(&m, 0, sizeof(m)); m.msg_name = (caddr_t)&dst6; m.msg_namelen = sizeof(dst6); iov[0].iov_base = (char *)buf; iov[0].iov_len = buflen; m.msg_iov = iov; m.msg_iovlen = 1; memset(cmsgbuf, 0, sizeof(cmsgbuf)); cm = (struct cmsghdr *)cmsgbuf; m.msg_control = (caddr_t)cm; m.msg_controllen = CMSG_SPACE(sizeof(struct in6_pktinfo)); cm->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo)); cm->cmsg_level = IPPROTO_IPV6; cm->cmsg_type = IPV6_PKTINFO; pi = (struct in6_pktinfo *)CMSG_DATA(cm); memcpy(&pi->ipi6_addr, &src6.sin6_addr, sizeof(src6.sin6_addr)); pi->ipi6_ifindex = ifindex; plog(PLOG_DEBUG, PLOGLOC, NULL, "src6 %s %d\n", rcs_sa2str((struct sockaddr *)&src6), src6.sin6_scope_id); plog(PLOG_DEBUG, PLOGLOC, NULL, "dst6 %s %d\n", rcs_sa2str((struct sockaddr *)&dst6), dst6.sin6_scope_id); for (i = 0; i < cnt; i++) { len = sendmsg(s, &m, 0 /*MSG_DONTROUTE */ ); if (len < 0) { plog(PLOG_INTERR, PLOGLOC, NULL, "sendmsg (%s)\n", strerror(errno)); return -1; } plog(PLOG_DEBUG, PLOGLOC, NULL, "%d times of %d bytes message will be sent " "to %s\n", i + 1, len, rcs_sa2str(dst)); } plogdump(PLOG_DEBUG, PLOGLOC, 0, (char *)buf, buflen); return len; } #endif default: { int needclose = 0; int sendsock; if (rcs_cmpsa((struct sockaddr *)&ss, src) == 0) { sendsock = s; needclose = 0; } else { int yes = 1; /* * Use newly opened socket for sending packets. * NOTE: this is unsafe, because if the peer is quick enough * the packet from the peer may be queued into sendsock. * Better approach is to prepare bind'ed udp sockets for * each of the interface addresses. */ sendsock = socket(src->sa_family, SOCK_DGRAM, 0); if (sendsock < 0) { plog(PLOG_INTERR, PLOGLOC, NULL, "socket (%s)\n", strerror(errno)); return -1; } #ifdef SO_REUSEPORT if (setsockopt(sendsock, SOL_SOCKET, SO_REUSEPORT, (void *)&yes, sizeof(yes)) < 0) { plog(PLOG_INTERR, PLOGLOC, NULL, "setsockopt (%s)\n", strerror(errno)); close(sendsock); return -1; } #else #ifdef SO_REUSEADDR if (setsockopt(sendsock, SOL_SOCKET, SO_REUSEADDR, (void *)&yes, sizeof(yes)) < 0) { plog(PLOG_INTERR, PLOGLOC, NULL, "setsockopt (%s)\n", strerror(errno)); close(sendsock); return -1; } #else #error #endif #endif #ifdef IPV6_USE_MIN_MTU if (src->sa_family == AF_INET6 && setsockopt(sendsock, IPPROTO_IPV6, IPV6_USE_MIN_MTU, (void *)&yes, sizeof(yes)) < 0) { plog(PLOG_INTERR, PLOGLOC, NULL, "setsockopt (%s)\n", strerror(errno)); close(sendsock); return -1; } #endif if (rcf_interface_head->application_bypass != RCT_BOOL_OFF && setsockopt_bypass(sendsock, src->sa_family) < 0) { close(sendsock); return -1; } if (bind (sendsock, (struct sockaddr *)src, SOCKADDR_LEN(src)) < 0) { plog(PLOG_INTERR, PLOGLOC, NULL, "bind 1 (%s)\n", strerror(errno)); close(sendsock); return -1; } needclose = 1; } for (i = 0; i < cnt; i++) { #ifdef DEBUG extern uint32_t debug_send; static int send_count = 0; if (debug_send & (1 << (send_count++ % 32))) { /* simulate a network packet drop */ TRACE((PLOGLOC, "debug_send %d drop\n", send_count)); len = buflen; } else #endif len = sendto(sendsock, buf, buflen, 0, dst, SOCKADDR_LEN(dst)); if (len < 0) { plog(PLOG_INTERR, PLOGLOC, NULL, "sendto (%s)\n", strerror(errno)); if (needclose) close(sendsock); return len; } plog(PLOG_DEBUG, PLOGLOC, NULL, "%d times of %d bytes message will be sent " "to %s\n", i + 1, len, rcs_sa2str(dst)); } plogdump(PLOG_DEBUG, PLOGLOC, 0, (char *)buf, buflen); if (needclose) close(sendsock); return len; } } }