/* ****************************************************************************** * SOURCE FILE * * Document no: @(#) $Name: VXWORKS_ITER40_2019102207 $ $RCSfile: ipike2_payload_authentication.c,v $ $Revision: 1.26.10.7 $ * $Source: /home/interpeak/CVSRoot/ipike/src/ipike2_payload_authentication.c,v $ * $Author: zan $ $Date: 2013-08-05 10:04:01 $ * $State: Exp $ $Locker: $ * * INTERPEAK_COPYRIGHT_STRING * Design and implementation by Kenneth Jonsson ****************************************************************************** */ /* **************************************************************************** * 1 DESCRIPTION **************************************************************************** */ /* Authentication payload (IKE version 2) */ /* **************************************************************************** * 2 CONFIGURATION **************************************************************************** */ #include "ipike_config.h" /* **************************************************************************** * 3 INCLUDE FILES **************************************************************************** */ #ifdef IPIKE_USE_VERSION2 #include "ipike_h.h" #include "ipike_attributes.h" #include "ipike2_payload_authentication.h" #include "ipike_util.h" #include "ipike_sadb.h" #include "ipike_crypto.h" #include #include #include /* **************************************************************************** * 4 EXTERN PROTOTYPES **************************************************************************** */ /* **************************************************************************** * 5 DEFINES **************************************************************************** */ /* **************************************************************************** * 6 TYPES **************************************************************************** */ /* **************************************************************************** * 7 LOCAL PROTOTYPES **************************************************************************** */ /* **************************************************************************** * 8 DATA **************************************************************************** */ /* **************************************************************************** * 9 LOCAL FUNCTIONS **************************************************************************** */ /* *=========================================================================== * ipike_payload_authentication_data *=========================================================================== * Description: Returns a pointer to the authentication data in the payload. * Parameters: auth - a authentication payload. * Returns: A pointer to the authentication data. */ IP_STATIC Ip_u8* ipike_payload_authentication_data(Ipike2_auth_payload* auth) { return (Ip_u8*)auth + sizeof(Ipike2_auth_payload); } /* *=========================================================================== * ipike_payload_authentication_data_length *=========================================================================== * Description: Returns the length of the authentication data. * Parameters: auth - authentication payload. * Returns: The length of the authentication data (in bytes). */ IP_STATIC Ip_u16 ipike_payload_authentication_data_length(Ipike2_auth_payload* auth) { return IPIKE_PAYLOAD_DATA_LENGTH(auth->header.length, sizeof(Ipike2_auth_payload)); } /* *=========================================================================== * ipike_payload_authentication_get_digest_info *=========================================================================== */ IP_STATIC Ipike_error ipike_payload_authentication_get_digest_info( Ipike_config_auth* conf, Ipike_value* msg, Ipike_value* digest) { Ipike_error err; Ipike_value data; Ipike_value hash; Ip_u8 alg; digest->value = IP_NULL; data.value = IP_NULL; hash.value = IP_NULL; alg = ipike_crypto_hash_algorithm_from_cert(conf->certificate); if (IPIKE_SUCCESS != (err = ipike_crypto_hash(alg, msg, &hash))) { IPCOM_LOG0(ERR, "ipike_payload_authentication_get_digest_info() :: failed generate hash"); } else if (IPIKE_SUCCESS != (err = ipike_crypto_create_digest_info(alg, &hash, digest))) { IPCOM_LOG0(ERR, "ipike_payload_authentication_get_digest_info() :: failed encode digest info"); } if (IP_NULL != data.value) ipcom_free(data.value); if (IP_NULL != hash.value) ipcom_free(hash.value); return err; } /* *=========================================================================== * ipike_payload_authentication_verify_certificate *=========================================================================== */ IP_STATIC Ipike_error ipike_payload_authentication_verify_certificate( Ipike_config_auth* conf, Ipike_cert* cert) { Ipike_error err = IPIKE_SUCCESS; X509** trusted = IP_NULL; X509** ca = IP_NULL; X509_CRL** crls = IP_NULL; trusted = ipike_crypto_get_trusted_certs(conf->trusted_ca_store); ca = ipike_crypto_get_intermediate_ca_certs(cert, conf->intermediate_ca_store); if (trusted == IP_NULL) { IPCOM_LOG0(ERR, "ipike_payload_authentication_verify_certificate() :: failed to read trusted certificate"); err = IPIKE_INVALID_VALUE; } else { #ifdef IPIKE_USE_OCSP err = ipike_crypto_verify_certificate_ocsp(trusted, ca, cert->peer, cert->crls, cert->resp_peer); #else err = ipike_crypto_verify_certificate(trusted, ca, cert->peer, cert->crls); #endif } ipike_array_free((void**) trusted, (void(*)(void*)) X509_free); ipike_array_free((void**) ca, (void(*)(void*)) X509_free); ipike_array_free((void**) crls, (void(*)(void*)) X509_CRL_free); return err; } /* *=========================================================================== * ipike_payload_authentication_generate_pre_shared *=========================================================================== */ IP_STATIC Ipike_error ipike_payload_authentication_generate_pre_shared(Ip_u16 prf_alg, Ipike_config_auth* conf, Ipike_value* msg, Ipike_value* auth) { Ipike_error err = IPIKE_SUCCESS; Ip_u8* psk_buf = IP_NULL; int psk_buf_len = 0; const char* psk_id = conf->psk_id; Ip_u8* shared_key = (Ip_u8 *) conf->shared_key; Ip_size_t shared_key_len = shared_key ? ipcom_strlen(conf->shared_key) : 0; if (psk_id) { if (ipcom_key_db_buf_get(psk_id, IP_NULL, &psk_buf_len) != IPCOM_SUCCESS) { IPCOM_LOG1(ERR, "ipike_payload_authentication_generate_pre_shared()"\ " :: failed to get psk_id: %s, from secure key db", psk_id); } psk_buf = ipcom_malloc((Ip_size_t)psk_buf_len); if (psk_buf == IP_NULL) return IPIKE_OUT_OF_MEMORY; if (ipcom_key_db_buf_get(psk_id, psk_buf, &psk_buf_len) != IPCOM_SUCCESS) { IPCOM_LOG1(ERR, "ipike_payload_authentication_generate_pre_shared()"\ " :: failed to get psk_id: %s, from secure key db", psk_id); } shared_key = psk_buf; shared_key_len = (Ip_size_t) psk_buf_len; } else if ( ipike_util_str_is_hex(conf->shared_key) ) { psk_buf = ipike_util_str_hex2bin(conf->shared_key, &shared_key_len); if (psk_buf == IP_NULL) return IPIKE_OUT_OF_MEMORY; shared_key = psk_buf; } err = ipike_crypto_compute_auth_pre_shared_secret(prf_alg, shared_key, shared_key_len, msg, auth); if (IPIKE_SUCCESS != err) { IPCOM_LOG0(ERR, "ipike_payload_authentication_generate_pre_shared() ::"\ " failed to generate eap auth"); err = IPIKE_ISAKMP_AUTHENTICATION_FAILED; } #ifdef IP_DEBUG (void)ipike_print_memory(IPCOM_LOG_DEBUG, "Auth:\n", auth->value, auth->len); #endif if (psk_buf != IP_NULL) ipcom_free(psk_buf); return err; } /* *=========================================================================== * ipike_payload_authentication_verify_pre_shared *=========================================================================== */ IP_STATIC Ipike_error ipike_payload_authentication_verify_pre_shared( Ip_u16 prf_alg, Ipike_config_auth* conf, Ipike_value* msg, Ipike_value* auth) { Ipike_error err; Ipike_value auth2; auth2.value = IP_NULL; err = ipike_payload_authentication_generate_pre_shared(prf_alg, conf, msg, &auth2); if (IPIKE_SUCCESS != err) return err; if (auth->len != auth2.len || ipcom_memcmp(auth->value, auth2.value, auth2.len)) err = IPIKE_ISAKMP_AUTHENTICATION_FAILED; ipcom_free(auth2.value); return err; } /* *=========================================================================== * ipike_payload_authentication_generate_rsa_signature *=========================================================================== */ IP_STATIC Ipike_error ipike_payload_authentication_generate_rsa_signature( Ipike_config_auth* conf, Ipike_value* msg, Ipike_value* auth) { Ipike_error err; Ipike_value digest; digest.value = IP_NULL; err = ipike_payload_authentication_get_digest_info(conf, msg, &digest); if (IPIKE_SUCCESS != err) { IPCOM_LOG0(ERR, "ipike_payload_authentication_generate_rsa_signature() :: failed to generate digest"); } else if (IPIKE_SUCCESS != (err = ipike_crypto_compute_rsa_sign(conf->key_id, conf->private_key, &digest, auth))) { IPCOM_LOG0(ERR, "ipike_payload_authentication_generate_rsa_signature() :: failed to compute signature"); } if (IP_NULL != digest.value) ipcom_free(digest.value); return err; } /* *=========================================================================== * ipike_payload_authentication_verify_rsa_signature *=========================================================================== */ IP_STATIC Ipike_error ipike_payload_authentication_verify_rsa_signature( Ipike_config_auth* conf, Ipike_value* msg, Ipike_cert* cert, Ipike_value* auth) { Ipike_error err; Ipike_value digest; digest.value = IP_NULL; digest.len = 0; if (IPIKE_SUCCESS != (err = ipike_crypto_verify_recover_rsa_sign( cert->peer, auth, &digest))) { IPCOM_LOG0(ERR, "Failed to recover digest from signature"); err = IPIKE_ISAKMP_AUTHENTICATION_FAILED; } else if (IPIKE_SUCCESS != (err = ipike_crypto_verify_data(msg, &digest))) { IPCOM_LOG0(ERR, "Failed to verify signature"); err = IPIKE_ISAKMP_AUTHENTICATION_FAILED; } else if (IPIKE_SUCCESS != (err = ipike_payload_authentication_verify_certificate( conf, cert))) { IPCOM_LOG0(ERR, "Failed to verify certificate"); err = IPIKE_ISAKMP_AUTHENTICATION_FAILED; } if (IP_NULL != digest.value) ipcom_free(digest.value); return err; } /* *=========================================================================== * ipike_payload_authentication_generate_dsa_signature *=========================================================================== */ IP_STATIC Ipike_error ipike_payload_authentication_generate_dsa_signature( Ipike_config_auth* conf, Ipike_value* msg, Ipike_value* auth) { Ipike_error err; Ip_u8 alg; Ipike_value hash; alg = IPIKE_ATTR_HASH_SHA1; /* always */ hash.value = IP_NULL; if (IPIKE_SUCCESS != (err = ipike_crypto_hash(alg, msg, &hash))) { IPCOM_LOG0(ERR, "ipike_payload_authentication_generate_dsa_signature() :: failed generate hash"); } else if (IPIKE_SUCCESS != (err = ipike_crypto_compute_dsa_sign(conf->key_id, conf->private_key, &hash, auth))) { IPCOM_LOG0(ERR, "ipike_payload_authentication_generate_dsa_signature() :: failed to compute signature"); } if (IP_NULL != hash.value) ipcom_free(hash.value); return err; } /* *=========================================================================== * ipike_payload_authentication_verify_dsa_signature *=========================================================================== */ IP_STATIC Ipike_error ipike_payload_authentication_verify_dsa_signature( Ipike_config_auth* conf, Ipike_value* msg, Ipike_cert* cert, Ipike_value* auth) { Ipike_error err; Ip_u8 alg; Ipike_value hash; hash.value = IP_NULL; alg = IPIKE_ATTR_HASH_SHA1; /* always */ if (IPIKE_SUCCESS != (err = ipike_crypto_hash(alg, msg, &hash))) { IPCOM_LOG0(ERR, "ipike_payload_authentication_verify_dsa_signature() :: failed generate hash"); } else if (IPIKE_SUCCESS != (err = ipike_crypto_verify_dsa_sign( cert->peer, &hash, auth))) { IPCOM_LOG0(ERR, "Failed to verify signature"); err = IPIKE_ISAKMP_AUTHENTICATION_FAILED; } else if (IPIKE_SUCCESS != (err = ipike_payload_authentication_verify_certificate( conf, cert))) { IPCOM_LOG0(ERR, "Failed to verify certificate"); err = IPIKE_ISAKMP_AUTHENTICATION_FAILED; } if (IP_NULL != hash.value) ipcom_free(hash.value); return err; } /* **************************************************************************** * 10 PUBLIC FUNCTIONS **************************************************************************** */ /* *=========================================================================== * ipike_payload_authentication_create *=========================================================================== */ IP_GLOBAL Ipike_error ipike_payload_authentication_create( Ipike2_auth* auth, Ipike2_auth_payload** payload) { Ipike2_auth_payload* auth_payload; if ((auth->data.value == IP_NULL) || (auth->data.len == 0)) { *payload = IP_NULL; } else { if (IP_NULL == (auth_payload = ipcom_calloc(1, sizeof(Ipike2_auth_payload) + auth->data.len))) { IP_PANIC(); return IPIKE_OUT_OF_MEMORY; } auth_payload->header.length = ip_htons((Ip_u16)(sizeof(*auth_payload) + auth->data.len)); auth_payload->header.next_payload = IPIKE2_PAYLOAD_AUTHENTICATION; auth_payload->method = auth->method; ipcom_memcpy(ipike_payload_authentication_data(auth_payload), auth->data.value, auth->data.len); *payload = auth_payload; } /* Free auth, so it may not be resued */ ipike_payload_authentication_free(auth); return IPIKE_SUCCESS; } /* *=========================================================================== * ipike_payload_authentication_free *=========================================================================== */ IP_GLOBAL void ipike_payload_authentication_free(Ipike2_auth* auth) { IPIKE_FREEP(auth->data.value); ipcom_memset(auth, 0, sizeof(*auth)); return; } /* *=========================================================================== * ipike_payload_authentication_check *=========================================================================== */ IP_GLOBAL Ipike_error ipike_payload_authentication_check(Ipike2_auth_payload* auth) { switch (auth->method) { case IPIKE2_AUTH_PRE_SHARED_KEY: case IPIKE2_AUTH_DSS_SIGNATURE: case IPIKE2_AUTH_RSA_SIGNATURE: return IPIKE_SUCCESS; } IPCOM_LOG2(ERR, "ipike_payload_authentication_check() :: %s (%d) is a unsupported authentication method", ipike_attribute_auth_method_to_string(auth->method), auth->method); return IPIKE_INVALID_VALUE; } /* *=========================================================================== * ipike_payload_authentication_print *=========================================================================== */ IP_GLOBAL void ipike_payload_authentication_print(Ipike2_auth_payload* auth) { IPCOM_LOG1(DEBUG2, " method: '%s'", ipike_attribute_auth_method_to_string_v2(auth->method)); (void)ipike_print_memory(IPCOM_LOG_DEBUG2, " data: \n", ipike_payload_authentication_data(auth), ipike_payload_authentication_data_length(auth)); } /* *=========================================================================== * ipike_payload_authentication_extract *=========================================================================== */ IP_GLOBAL Ipike_error ipike_payload_authentication_extract( Ipike2_auth_payload* payload, Ipike2_auth* auth) { auth->method = payload->method; auth->data.len = ipike_payload_authentication_data_length(payload); ipcom_free(auth->data.value); if (IP_NULL == (auth->data.value = ipcom_malloc(auth->data.len))) { IP_PANIC(); return IPIKE_OUT_OF_MEMORY; } ipcom_memcpy(auth->data.value, ipike_payload_authentication_data(payload), auth->data.len); return IPIKE_SUCCESS; } /* *=========================================================================== * ipike_payload_authentication_generate_message *=========================================================================== */ IP_STATIC Ipike_error ipike_payload_authentication_generate_message( Ipike2_id* id, Ipike_value* key, Ipike_value* nonce, Ipike_value* data, Ipike_value* msg, Ip_u16 prf_alg) { Ipike_value tmp; #ifdef IP_DEBUG (void)ipike_print_memory(IPCOM_LOG_DEBUG2, "Id:\n", id->data.value, id->data.len); (void)ipike_print_memory(IPCOM_LOG_DEBUG2, "Key:\n", key->value, key->len); (void)ipike_print_memory(IPCOM_LOG_DEBUG2, "Nonce:\n", nonce->value, nonce->len); #endif (void)ipike_set_value(msg, data); (void)ipike_append_value(msg, nonce); tmp.len = 4; tmp.value = ipcom_malloc(tmp.len); if (tmp.value ==IP_NULL) return IPIKE_FAILED; ipcom_memset(tmp.value, 0, tmp.len); tmp.value[0] = id->info.id_type; ipcom_memcpy(tmp.value + 1, id->info.reserved, 3); (void)ipike_append_value(&tmp, &id->data); (void)ipike_crypto_compute_prf(prf_alg, key, &tmp, IP_NULL, IP_NULL, &tmp); (void)ipike_append_value(msg, &tmp); IPIKE_FREEP(tmp.value); (void)ipike_print_memory(IPCOM_LOG_DEBUG2, "Message:\n", msg->value, msg->len); return IPIKE_SUCCESS; } /* *=========================================================================== * ipike_payload_authentication_generate *=========================================================================== */ IP_GLOBAL Ipike_error ipike_payload_authentication_generate( Ip_u8 auth_method, Ip_u16 prf_alg, Ipike_config_auth* conf, Ipike2_id* id, Ipike_value* key, Ipike_value* nonce, Ipike_value* msg, Ipike2_auth* auth) { Ipike_error err = IPIKE_SUCCESS; Ipike_value data = {0}; if (IPIKE_SUCCESS != (err = ipike_payload_authentication_generate_message( id, key, nonce, msg, &data, prf_alg))) return err; msg = &data; auth->method = auth_method; ipcom_free(auth->data.value); auth->data.value = IP_NULL; auth->data.len = 0; switch (auth->method) { case IPIKE2_AUTH_PRE_SHARED_KEY: err = ipike_payload_authentication_generate_pre_shared(prf_alg, conf, msg, &auth->data); break; case IPIKE2_AUTH_RSA_SIGNATURE: err = ipike_payload_authentication_generate_rsa_signature( conf, msg, &auth->data); break; case IPIKE2_AUTH_DSS_SIGNATURE: err = ipike_payload_authentication_generate_dsa_signature( conf, msg, &auth->data); break; default: IPCOM_LOG1(ERR, "ipike_payload_authentication_generate() :: Unsupported authentication method %d", auth->method); err = IPIKE_ISAKMP_AUTHENTICATION_FAILED; break; } ipcom_free(data.value); return err; } /* *=========================================================================== * ipike_payload_authentication_generate_eap *=========================================================================== */ IP_GLOBAL Ipike_error ipike_payload_authentication_generate_eap( Ip_u8* shared_key, Ip_u32 shared_key_len, Ip_u16 prf_alg, Ipike2_id* id, Ipike_value* key, Ipike_value* nonce, Ipike_value* msg, Ipike2_auth* auth) { Ipike_error err = IPIKE_SUCCESS; Ipike_value data; if (shared_key == IP_NULL || shared_key_len == 0) { shared_key = key->value; shared_key_len = (Ip_u32) key->len; } err = ipike_payload_authentication_generate_message(id, key, nonce, msg, &data, prf_alg); if (IPIKE_SUCCESS != err) return err; msg = &data; auth->method = IPIKE2_AUTH_PRE_SHARED_KEY; ipcom_free(auth->data.value); auth->data.value = IP_NULL; auth->data.len = 0; err = ipike_crypto_compute_auth_pre_shared_secret(prf_alg, shared_key, shared_key_len, msg, &auth->data); if (IPIKE_SUCCESS != err) { IPCOM_LOG0(ERR, "ipike_payload_authentication_generate_eap() ::"\ " failed to generate eap auth"); err = IPIKE_ISAKMP_AUTHENTICATION_FAILED; } IPIKE_FREEP(data.value); return err; } /* *=========================================================================== * ipike_payload_accept_authentication_method *=========================================================================== */ IP_STATIC Ip_bool ipike_payload_accept_authentication_method( const char* str_methods, Ip_u8 method) { char* str = IP_NULL; Ip_u8 n = 0xff; while ((n != method) && (str_methods[0] != 0) && (ipike_parse_get_string(&str_methods, ',', &str) == IPIKE_SUCCESS)) { if (IPIKE_SUCCESS != ipike_attribute_auth_method_from_string_v2(str, &n)) n = 0xff; ipcom_free(str); } return (n == method); } /* *=========================================================================== * ipike_payload_authentication_verify *=========================================================================== */ IP_GLOBAL Ipike_error ipike_payload_authentication_verify( Ip_u16 prf_alg, Ipike_config_auth* conf, Ipike2_id* id, Ipike_value* key, Ipike_value* nonce, Ipike_value* msg, Ipike_cert* cert, Ipike2_auth* auth) { Ipike_error err = IPIKE_SUCCESS; Ipike_value data; if (!ipike_payload_accept_authentication_method(conf->method, auth->method)) { IPCOM_LOG0(ERR, "ipike_payload_authentication_verify() :: Authentication method not accepted"); return IPIKE_ISAKMP_AUTHENTICATION_FAILED; } if (IPIKE_SUCCESS != (err = ipike_payload_authentication_generate_message( id, key, nonce, msg, &data, prf_alg))) return err; msg = &data; switch (auth->method) { case IPIKE2_AUTH_PRE_SHARED_KEY: err = ipike_payload_authentication_verify_pre_shared(prf_alg, conf, msg, &auth->data); break; case IPIKE2_AUTH_RSA_SIGNATURE: err = ipike_payload_authentication_verify_rsa_signature(conf, msg, cert, &auth->data); break; case IPIKE2_AUTH_DSS_SIGNATURE: err = ipike_payload_authentication_verify_dsa_signature(conf, msg, cert, &auth->data); break; default: IPCOM_LOG1(ERR, "ipike_payload_authentication_verify() :: Unsupported authentication method %d", auth->method); err = IPIKE_ISAKMP_AUTHENTICATION_FAILED; break; } IPIKE_FREEP(data.value); /* Free auth, so it may not be resued */ ipike_payload_authentication_free(auth); return err; } /* *=========================================================================== * ipike_payload_authentication_verify_eap *=========================================================================== */ IP_GLOBAL Ipike_error ipike_payload_authentication_verify_eap( Ip_u8* shared_key, Ip_u32 shared_key_len, Ip_u16 prf_alg, Ipike2_id* id, Ipike_value* key, Ipike_value* nonce, Ipike_value* msg, Ipike2_auth* auth) { Ipike_error err = IPIKE_SUCCESS; Ipike2_auth auth2 = {0}; err = ipike_payload_authentication_generate_eap(shared_key, shared_key_len, prf_alg, id, key, nonce, msg, &auth2); if (err != IPIKE_SUCCESS) { IPCOM_LOG0(ERR, "ipike_payload_authentication_verify() :: Failed to generate AUTH payload"); err = IPIKE_ISAKMP_AUTHENTICATION_FAILED; } else { if ((auth->method != auth2.method) || (auth->data.len != auth2.data.len) || (memcmp(auth->data.value, auth2.data.value, auth->data.len) != 0)) { IPCOM_LOG0(ERR, "ipike_payload_authentication_verify() :: Failed to verify AUTH payload"); err = IPIKE_ISAKMP_AUTHENTICATION_FAILED; } ipike_payload_authentication_free(&auth2); } /* Free auth, so it may not be resued */ ipike_payload_authentication_free(auth); return err; } #else int ipike_payload_authentication_empty_file = 0; #endif /* IPIKE_USE_VERSION2 */ /* **************************************************************************** * END OF FILE **************************************************************************** */