891 lines
30 KiB
C
891 lines
30 KiB
C
/*
|
|
******************************************************************************
|
|
* SOURCE FILE
|
|
*
|
|
* Document no: @(#) $Name: VXWORKS_ITER40_2019102207 $ $RCSfile: ipike_payload_certificate.c,v $ $Revision: 1.19.10.4 $
|
|
* $Source: /home/interpeak/CVSRoot/ipike/src/ipike_payload_certificate.c,v $
|
|
* $Author: edahlber $ $Date: 2012-02-15 08:41:53 $
|
|
* $State: Exp $ $Locker: $
|
|
*
|
|
* INTERPEAK_COPYRIGHT_STRING
|
|
* Design and implementation by Kenneth Jonsson <kenneth@interpeak.se>
|
|
******************************************************************************
|
|
*/
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 1 DESCRIPTION
|
|
****************************************************************************
|
|
*/
|
|
|
|
/* Certificate payload (RFC 2408, chapter 3.9) */
|
|
/* IKE version 1 and 2 */
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 2 CONFIGURATION
|
|
****************************************************************************
|
|
*/
|
|
#include "ipike_config.h"
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 3 INCLUDE FILES
|
|
****************************************************************************
|
|
*/
|
|
|
|
#include "ipike_h.h"
|
|
#include "ipike_payload_certificate.h"
|
|
#include "ipike_crypto.h"
|
|
#include "ipike_util.h"
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 4 EXTERN PROTOTYPES
|
|
****************************************************************************
|
|
*/
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 5 DEFINES
|
|
****************************************************************************
|
|
*/
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 6 TYPES
|
|
****************************************************************************
|
|
*/
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 7 LOCAL PROTOTYPES
|
|
****************************************************************************
|
|
*/
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipike_payload_certificate_data
|
|
*===========================================================================
|
|
* Description: Returns a pointer to the certificate data in the payload.
|
|
* Parameters: cert - A certificate payload.
|
|
* Returns: A pointer to the certificate data.
|
|
*
|
|
*/
|
|
IP_STATIC Ip_u8*
|
|
ipike_payload_certificate_data(Ipike_cert_payload* hash);
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipike_payload_certificate_data_length
|
|
*===========================================================================
|
|
* Description: Returns the length of the certificate data.
|
|
* Parameters: cert - A certificate payload.
|
|
* Returns: The length of the certificate data (in bytes).
|
|
*
|
|
*
|
|
*/
|
|
IP_STATIC Ip_u16
|
|
ipike_payload_certificate_data_length(Ipike_cert_payload* cert);
|
|
|
|
#ifdef IPIKE_USE_OCSP
|
|
/*
|
|
*===========================================================================
|
|
* ipike_payload_certificate_req_data
|
|
*===========================================================================
|
|
* Description: Returns a pointer to the certificate data in the payload.
|
|
* Parameters: cert - A certificate payload.
|
|
* Returns: A pointer to the certificate data.
|
|
*
|
|
*/
|
|
IP_STATIC Ip_u8*
|
|
ipike_payload_certificate_req_data(Ipike_cert_req_payload* hash);
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipike_payload_certificate_data_length
|
|
*===========================================================================
|
|
* Description: Returns the length of the certificate data.
|
|
* Parameters: cert - A certificate payload.
|
|
* Returns: The length of the certificate data (in bytes).
|
|
*
|
|
*
|
|
*/
|
|
IP_STATIC Ip_u16
|
|
ipike_payload_certificate_req_data_length(Ipike_cert_req_payload* certreq);
|
|
|
|
#endif /* IPIKE_USE_OCSP */
|
|
/*
|
|
****************************************************************************
|
|
* 8 DATA
|
|
****************************************************************************
|
|
*/
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 9 LOCAL FUNCTIONS
|
|
****************************************************************************
|
|
*/
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipike_payload_certificate_data
|
|
*===========================================================================
|
|
*/
|
|
IP_STATIC Ip_u8*
|
|
ipike_payload_certificate_data(Ipike_cert_payload* cert)
|
|
{
|
|
return (Ip_u8*) cert + 5;
|
|
}
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipike_payload_certificate_data_length
|
|
*===========================================================================
|
|
*/
|
|
IP_STATIC Ip_u16
|
|
ipike_payload_certificate_data_length(Ipike_cert_payload* cert)
|
|
{
|
|
return IPIKE_PAYLOAD_DATA_LENGTH(cert->header.length, 5);
|
|
}
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipike_payload_certificate_req_data
|
|
*===========================================================================
|
|
*/
|
|
IP_STATIC Ip_u8*
|
|
ipike_payload_certificate_req_data(Ipike_cert_req_payload* hash)
|
|
{
|
|
return (Ip_u8*) hash + 5;
|
|
}
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipike_payload_certificate_req_data_length
|
|
*===========================================================================
|
|
*/
|
|
IP_STATIC Ip_u16
|
|
ipike_payload_certificate_req_data_length(Ipike_cert_req_payload* certreq)
|
|
{
|
|
return IPIKE_PAYLOAD_DATA_LENGTH(certreq->header.length, 5);
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipike_payload_certificate_encode_type_to_string
|
|
*===========================================================================
|
|
*/
|
|
IP_STATIC const char*
|
|
ipike_payload_certificate_encode_type_to_string(Ip_u8 type)
|
|
{
|
|
const char* s;
|
|
if ((ipike_map_string(ipike.cert_encode_type_map, type, &s)))
|
|
return "unknown certificate encoding type";
|
|
return s;
|
|
}
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 10 PUBLIC FUNCTIONS
|
|
****************************************************************************
|
|
*/
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipike_payload_certificate_free
|
|
*===========================================================================
|
|
*/
|
|
IP_GLOBAL void
|
|
ipike_payload_certificate_free(Ipike_cert* cert)
|
|
{
|
|
if (IP_NULL != cert->local)
|
|
X509_free(cert->local);
|
|
if (IP_NULL != cert->peer)
|
|
X509_free(cert->peer);
|
|
if (IP_NULL != cert->peer_url)
|
|
ipcom_free((void*)cert->peer_url);
|
|
ipike_array_free((void**)cert->crls, (void(*)(void*)) X509_CRL_free);
|
|
ipike_array_free((void**)cert->ca, (void(*)(void*)) X509_free);
|
|
ipike_array_free((void**)cert->trusted, (void(*)(void*)) X509_free);
|
|
|
|
#ifdef IPIKE_USE_OCSP
|
|
if (IP_NULL != cert->resp_local)
|
|
OCSP_RESPONSE_free(cert->resp_local);
|
|
if (IP_NULL != cert->resp_peer)
|
|
OCSP_RESPONSE_free(cert->resp_peer);
|
|
#endif
|
|
|
|
ipcom_memset(cert, 0, sizeof(Ipike_cert));
|
|
}
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipike_payload_certificate_create
|
|
*===========================================================================
|
|
*/
|
|
IP_GLOBAL Ipike_error
|
|
ipike_payload_certificate_create(
|
|
X509* cert,
|
|
const char *url,
|
|
Ipike_cert_payload** payload
|
|
)
|
|
{
|
|
unsigned char* cert_data;
|
|
int cert_len;
|
|
int payload_len;
|
|
int encoding = IPIKE_CERT_X509_SIGNATURE;
|
|
|
|
if (IP_NULL == cert)
|
|
{
|
|
IPCOM_LOG0(ERR, "ipike_payload_certificate_create: no certificate specified, check configuration");
|
|
return IPIKE_INVALID_VALUE;
|
|
}
|
|
|
|
cert_len = i2d_X509(cert, IP_NULL);
|
|
if (cert_len <= 0)
|
|
{
|
|
IPCOM_LOG0(ERR,
|
|
"ipike_payload_certificate_create: failed to determine the length of the certificate");
|
|
return IPIKE_INVALID_VALUE;
|
|
}
|
|
|
|
payload_len = 5 + cert_len;
|
|
if (IP_NULL == (*payload = ipcom_calloc(1, (Ip_size_t) payload_len)))
|
|
{
|
|
IP_PANIC();
|
|
return IPIKE_OUT_OF_MEMORY;
|
|
}
|
|
|
|
cert_data = (unsigned char*)ipike_payload_certificate_data(*payload);
|
|
if (i2d_X509(cert, &cert_data) < 0)
|
|
{
|
|
IPIKE_FREEP(*payload);
|
|
IPCOM_LOG0(ERR, "ipike_payload_certificate_create: failed to encode the certificate");
|
|
return IPIKE_INVALID_VALUE;
|
|
}
|
|
|
|
#ifdef IPIKE_USE_VERSION2
|
|
if ( IP_NULL != url )
|
|
{
|
|
Ip_u8 *message_digest;
|
|
Ipike_value data;
|
|
Ipike_error err;
|
|
Ip_size_t url_len;
|
|
|
|
/* Length of URL including NULL termination */
|
|
url_len = ipcom_strlen(url);
|
|
IPCOM_LOG0(DEBUG2, "ipike_payload_certificate_create: Hash and URL enabled, sending hash of certificate");
|
|
|
|
/* Payload header + SHA1_HASH + url_base_len + NULL termination */
|
|
payload_len = 5 + SHA_DIGEST_LENGTH + (int)url_len + SHA_DIGEST_LENGTH + SHA_DIGEST_LENGTH + 1;
|
|
|
|
message_digest = ipcom_malloc((Ip_size_t)payload_len);
|
|
|
|
if ( !message_digest )
|
|
{
|
|
IP_PANIC();
|
|
return IPIKE_OUT_OF_MEMORY;
|
|
}
|
|
|
|
data.value = ipike_payload_certificate_data(*payload);
|
|
data.len = (Ip_size_t) cert_len;
|
|
|
|
if ( (err = ipike_crypto_sha_hash(&data, message_digest + 5)) != IPIKE_SUCCESS )
|
|
{
|
|
IPIKE_FREEP(*payload);
|
|
ipcom_free(message_digest);
|
|
IPCOM_LOG0(ERR, "ipike_payload_certificate_create: Failed to create SHA1 hash of the certificate");
|
|
return err;
|
|
}
|
|
|
|
/* Add URL base */
|
|
memcpy(message_digest + 5 + SHA_DIGEST_LENGTH, url, url_len);
|
|
|
|
/* Add hex representation of certificate, this will add a NULL termination */
|
|
ipike_bin2hex(message_digest + 5, SHA_DIGEST_LENGTH, (char *) message_digest + 5 + SHA_DIGEST_LENGTH + url_len);
|
|
|
|
ipcom_free(*payload);
|
|
*payload = (Ipike_cert_payload *) message_digest;
|
|
encoding = IPIKE_CERT_X509_HASH_AND_URL;
|
|
}
|
|
#else
|
|
/* Send hash of certificate is only supported in IKEv2 */
|
|
ip_assert(url == IP_NULL);
|
|
#endif
|
|
|
|
(*payload)->header.length = (Ip_u16)ip_htons(payload_len);
|
|
(*payload)->header.next_payload = IPIKE_PAYLOAD_CERTIFICATE;
|
|
(*payload)->cert_encoding = (Ip_u8) encoding;
|
|
|
|
return IPIKE_SUCCESS;
|
|
}
|
|
|
|
|
|
#ifdef IPIKE_USE_OCSP
|
|
/*
|
|
*===========================================================================
|
|
* ipike_payload_certificate_ocsp_create
|
|
*===========================================================================
|
|
*/
|
|
IP_GLOBAL Ipike_error
|
|
ipike_payload_certificate_ocsp_create(OCSP_RESPONSE* resp, Ipike_cert_payload** payload)
|
|
{
|
|
int resp_len;
|
|
int payload_len;
|
|
unsigned char* resp_data;
|
|
|
|
if (IP_NULL == resp)
|
|
{
|
|
IPCOM_LOG0(ERR, "ipike_payload_certificate_ocsp_create: no response specified, check configuration");
|
|
return IPIKE_INVALID_VALUE;
|
|
}
|
|
resp_len = i2d_OCSP_RESPONSE(resp, IP_NULL);
|
|
if (resp_len <= 0)
|
|
{
|
|
IPCOM_LOG0(ERR, "ipike_payload_certificate_ocsp_create: failed to determine the length of the response");
|
|
return IPIKE_INVALID_VALUE;
|
|
}
|
|
|
|
payload_len = 5 + resp_len;
|
|
if (IP_NULL == (*payload = ipcom_calloc(1, (Ip_size_t) payload_len)))
|
|
{
|
|
IP_PANIC();
|
|
return IPIKE_OUT_OF_MEMORY;
|
|
}
|
|
|
|
resp_data = (unsigned char*)ipike_payload_certificate_data(*payload);
|
|
if (i2d_OCSP_RESPONSE(resp, &resp_data) < 0)
|
|
{
|
|
IPCOM_LOG0(ERR, "ipike_payload_certificate_ocsp_create: failed to encode the response");
|
|
return IPIKE_INVALID_VALUE;
|
|
}
|
|
(*payload)->header.length = (Ip_u16) ip_htons(payload_len);
|
|
(*payload)->header.next_payload = IPIKE_PAYLOAD_CERTIFICATE;
|
|
(*payload)->cert_encoding = IPIKE_OCSP_CONTENT;
|
|
|
|
return IPIKE_SUCCESS;
|
|
}
|
|
|
|
#endif /* #ifdef IPIKE_USE_OCSP */
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipike_payload_certificate_req_create
|
|
*===========================================================================
|
|
*/
|
|
IP_GLOBAL Ipike_error
|
|
ipike_payload_certificate_req_create_v1(
|
|
Ipike_cert_req_payload** payload,
|
|
X509* ca_cert)
|
|
{
|
|
Ip_size_t payload_len = 0;
|
|
Ip_u8 *payload_data = IP_NULL;
|
|
X509_NAME *x509_name = IP_NULL;
|
|
int name_len = 0;
|
|
|
|
/* No trusted CA certificates => no certificate request payload */
|
|
if ( !ca_cert )
|
|
return IPIKE_SUCCESS;
|
|
|
|
/* Ignore non CA certificate */
|
|
if ( !ipike_crypto_is_ca_certificate(ca_cert) )
|
|
{
|
|
IPCOM_LOG0(DEBUG2, "ipike_payload_certificate_req_create_v1() :: "\
|
|
" skipping non-CA certificate");
|
|
return IPIKE_SUCCESS;
|
|
}
|
|
|
|
x509_name = X509_get_subject_name(ca_cert);
|
|
|
|
/* Should not happen, skip this CA if it happens */
|
|
if (!x509_name)
|
|
return IPIKE_SUCCESS;
|
|
|
|
name_len = i2d_X509_NAME(x509_name, IP_NULL);
|
|
|
|
/* Should not happen, skip this CA if it happens */
|
|
if ( name_len < 0 )
|
|
return IPIKE_FAILED;
|
|
|
|
IPCOM_LOG0(DEBUG2, "ipike_payload_certificate_req_create_v1() :: "\
|
|
" adding CA subject info into certificate request");
|
|
|
|
/* Calculate payload size */
|
|
payload_len = (Ip_size_t)name_len + IPIKE_CERT_REQ_HEADER_LENGTH;
|
|
|
|
/* Allocate payload */
|
|
if (IP_NULL == (*payload = ipcom_calloc(1, payload_len)))
|
|
{
|
|
IP_PANIC();
|
|
return IPIKE_OUT_OF_MEMORY;
|
|
}
|
|
|
|
/* Get payload data pointer */
|
|
payload_data = ipike_payload_certificate_req_data(*payload);
|
|
|
|
/* Encode to DER format into the payload data */
|
|
name_len = i2d_X509_NAME(x509_name, &payload_data);
|
|
|
|
if ( name_len < 0 )
|
|
{
|
|
|
|
IPCOM_LOG0(ERR, "ipike_payload_certificate_req_create_v1() :: "\
|
|
" failed to decode CA subject name");
|
|
ipcom_free(*payload);
|
|
*payload = IP_NULL;
|
|
|
|
/* Skip this CA */
|
|
return IPIKE_SUCCESS;
|
|
}
|
|
|
|
/* Set the rest of the payload fields */
|
|
(*payload)->cert_encoding = IPIKE_CERT_X509_SIGNATURE;
|
|
(*payload)->header.next_payload = IPIKE_PAYLOAD_CERTIFICATE_REQUEST;
|
|
(*payload)->header.length = (Ip_u16) ip_htons(payload_len);
|
|
|
|
return IPIKE_SUCCESS;
|
|
}
|
|
|
|
|
|
#ifdef IPIKE_USE_VERSION2
|
|
/*
|
|
*===========================================================================
|
|
* ipike_payload_certificate_req_create
|
|
*===========================================================================
|
|
*/
|
|
IP_GLOBAL Ipike_error
|
|
ipike_payload_certificate_req_create_v2(
|
|
Ipike_cert_req_payload** payload,
|
|
Ipike_cert *cert)
|
|
{
|
|
Ip_size_t payload_len = 0;
|
|
Ipike_error err = IPIKE_SUCCESS;
|
|
|
|
#ifdef IPIKE_USE_OCSP
|
|
/* Request OCSP */
|
|
if ( cert->resp_local != IP_NULL )
|
|
{
|
|
/* Only support CA signed OCSP responses*/
|
|
payload_len = IPIKE_CERT_REQ_HEADER_LENGTH;
|
|
|
|
if (IP_NULL == (*payload = ipcom_calloc(1, payload_len)))
|
|
{
|
|
IP_PANIC();
|
|
return IPIKE_OUT_OF_MEMORY;
|
|
}
|
|
|
|
(*payload)->cert_encoding = IPIKE_OCSP_CONTENT;
|
|
(*payload)->header.next_payload = IPIKE2_PAYLOAD_CERTIFICATE_REQUEST;
|
|
(*payload)->header.length = (Ip_u16) ip_htons(payload_len);
|
|
}
|
|
else if ( cert->trusted )
|
|
#endif
|
|
{
|
|
Ipike_value key_hashes;
|
|
Ip_u32 num_cas;
|
|
|
|
memset(&key_hashes, 0, sizeof(key_hashes));
|
|
IPCOM_LOG0(DEBUG2, "ipike_payload_certificate_req_create() :: adding public key hash to certificate request");
|
|
|
|
/* Get number of CAs we trust */
|
|
num_cas = ipike_array_size((void **)cert->trusted);
|
|
|
|
/* Send a sha1 hash of the public key of the CAs we trust */
|
|
payload_len = IPIKE_CERT_REQ_HEADER_LENGTH + (SHA_DIGEST_LENGTH * num_cas);
|
|
|
|
/* Allocate payload */
|
|
if (IP_NULL == (*payload = ipcom_calloc(1, payload_len)))
|
|
{
|
|
IP_PANIC();
|
|
return IPIKE_OUT_OF_MEMORY;
|
|
}
|
|
|
|
/* Get payload data pointer */
|
|
key_hashes.value = ipike_payload_certificate_req_data(*payload);
|
|
key_hashes.len = payload_len - IPIKE_CERT_REQ_HEADER_LENGTH;
|
|
|
|
/* Generate hashes */
|
|
err = ipike_crypto_generate_public_key_hashes(cert->trusted, &key_hashes);
|
|
|
|
if ( IPIKE_SUCCESS != err )
|
|
{
|
|
IPCOM_LOG1(DEBUG2,
|
|
"ipike_payload_certificate_req_create() :: failed to create hashes (%d)", err);
|
|
|
|
ipcom_free(*payload);
|
|
return err;
|
|
}
|
|
|
|
(*payload)->cert_encoding = IPIKE_CERT_X509_SIGNATURE;
|
|
(*payload)->header.next_payload = IPIKE2_PAYLOAD_CERTIFICATE_REQUEST;
|
|
(*payload)->header.length = (Ip_u16) ip_htons(payload_len);
|
|
}
|
|
|
|
|
|
return err;
|
|
}
|
|
#endif /* #ifdef IPIKE_USE_VERSION2 */
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipike_payload_certificate_check
|
|
*===========================================================================
|
|
*/
|
|
IP_GLOBAL Ipike_error
|
|
ipike_payload_certificate_check(Ipike_cert_payload* cert)
|
|
{
|
|
switch (cert->cert_encoding)
|
|
{
|
|
case IPIKE_CERT_X509_SIGNATURE:
|
|
return IPIKE_SUCCESS;
|
|
#ifdef IPIKE_USE_VERSION2
|
|
case IPIKE_CERT_X509_HASH_AND_URL:
|
|
return IPIKE_SUCCESS;
|
|
#endif
|
|
#ifdef IPIKE_USE_OCSP
|
|
case IPIKE_OCSP_CONTENT:
|
|
return IPIKE_SUCCESS;
|
|
#endif
|
|
default:
|
|
break;
|
|
}
|
|
|
|
IPCOM_LOG2(ERR,
|
|
"ipike_check_cert_payload: %s (%d) is a unsupported certificate encoding type",
|
|
ipike_payload_certificate_encode_type_to_string(cert->cert_encoding), cert->cert_encoding);
|
|
|
|
return IPIKE_INVALID_VALUE;
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipike_payload_certificate_request_check
|
|
*===========================================================================
|
|
*/
|
|
IP_GLOBAL Ipike_error
|
|
ipike_payload_certificate_request_check(Ipike_cert_req_payload* req)
|
|
{
|
|
switch (req->cert_encoding)
|
|
{
|
|
case IPIKE_CERT_X509_SIGNATURE:
|
|
return IPIKE_SUCCESS;
|
|
#ifdef IPIKE_USE_OCSP
|
|
case IPIKE_OCSP_CONTENT:
|
|
return IPIKE_SUCCESS;
|
|
#endif
|
|
case IPIKE_CERT_X509_HASH_AND_URL:
|
|
return IPIKE_SUCCESS;
|
|
/* Valid encodings but unsupported */
|
|
case IPIKE_CERT_PKCS_7:
|
|
case IPIKE_CERT_PGP:
|
|
case IPIKE_CERT_SIGNED_KEY:
|
|
case IPIKE_CERT_X509_KEY_EXCHANGE:
|
|
case IPIKE_CERT_KERBEROS_TOKENS:
|
|
case IPIKE_CERT_CRL:
|
|
case IPIKE_CERT_ARL:
|
|
case IPIKE_CERT_SPKI:
|
|
case IPIKE_CERT_X509_ATTRIBUTE:
|
|
IPCOM_LOG2(DEBUG2,
|
|
"ipike_check_certreq_payload() :: unsupported certificate request encoding type %s (%d)",
|
|
ipike_payload_certificate_encode_type_to_string(req->cert_encoding), req->cert_encoding);
|
|
return IPIKE_ISAKMP_CERT_TYPE_UNSUPPORTED;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
IPCOM_LOG2(DEBUG2,
|
|
"ipike_check_certreq_payload() :: invalid certificate request encoding type %s (%d)",
|
|
ipike_payload_certificate_encode_type_to_string(req->cert_encoding), req->cert_encoding);
|
|
|
|
/* Ignored, until we support multiple certificates */
|
|
return IPIKE_ISAKMP_INVALID_CERT_ENCODING;
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipike_payload_certificate_print
|
|
*===========================================================================
|
|
*/
|
|
IP_GLOBAL void
|
|
ipike_payload_certificate_print(Ipike_cert_payload* cert)
|
|
{
|
|
(void)ipike_payload_certificate_encode_type_to_string; /* lint */
|
|
IPCOM_LOG1(DEBUG2, " encoding type: %s",
|
|
ipike_payload_certificate_encode_type_to_string(cert->cert_encoding));
|
|
(void)ipike_print_memory(IPCOM_LOG_DEBUG2, " value:\n",
|
|
ipike_payload_certificate_data(cert),
|
|
ipike_payload_certificate_data_length(cert));
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipike_payload_certificate_request_print
|
|
*===========================================================================
|
|
*/
|
|
IP_GLOBAL void
|
|
ipike_payload_certificate_request_print(Ipike_cert_req_payload* req)
|
|
{
|
|
/* Ignored until we support multiple certificates */
|
|
IPCOM_LOG1(DEBUG2, " encoding type: %s",
|
|
ipike_payload_certificate_encode_type_to_string(req->cert_encoding));
|
|
|
|
(void)ipike_print_memory(IPCOM_LOG_DEBUG2, " value:\n",
|
|
ipike_payload_certificate_req_data(req),
|
|
ipike_payload_certificate_req_data_length(req));
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipike_payload_certificate_extract
|
|
*===========================================================================
|
|
*/
|
|
IP_GLOBAL Ipike_error
|
|
ipike_payload_certificate_extract(
|
|
Ipike_cert_payload* payload,
|
|
Ipike_cert* cert)
|
|
{
|
|
Ipike_error err;
|
|
Ip_u8* cert_data;
|
|
X509* x509;
|
|
#ifdef IPIKE_USE_OCSP
|
|
OCSP_RESPONSE* ocsp_resp;
|
|
#endif
|
|
|
|
switch (payload->cert_encoding)
|
|
{
|
|
case IPIKE_CERT_X509_SIGNATURE:
|
|
cert_data = ipike_payload_certificate_data(payload);
|
|
x509 = d2i_X509(IP_NULL, (const unsigned char**)&cert_data, ipike_payload_certificate_data_length(payload));
|
|
|
|
if (IP_NULL == x509)
|
|
{
|
|
IPCOM_LOG1(CRIT,
|
|
"ipike_payload_certificate_extract: failed to decode the certificate (type %s)",
|
|
ipike_payload_certificate_encode_type_to_string(payload->cert_encoding));
|
|
return IPIKE_INVALID_VALUE;
|
|
}
|
|
else
|
|
{
|
|
if (ipike_crypto_is_ca_certificate(x509))
|
|
{
|
|
if (IPIKE_SUCCESS != (err = ipike_array_add((void***)&cert->ca, x509)))
|
|
{
|
|
IPCOM_LOG0(CRIT, "ipike_payload_certificate_extract: Out of memory");
|
|
X509_free(x509);
|
|
return err;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (IP_NULL != cert->peer)
|
|
X509_free(cert->peer);
|
|
cert->peer = x509;
|
|
}
|
|
}
|
|
break;
|
|
|
|
#ifdef IPIKE_USE_VERSION2
|
|
case IPIKE_CERT_X509_HASH_AND_URL:
|
|
{
|
|
Ip_size_t cert_data_len;
|
|
|
|
if ( !ipike.use_hash_and_url )
|
|
{
|
|
IPCOM_LOG0(CRIT,
|
|
"ipike_payload_certificate_extract: hash and url support not enabled");
|
|
return IPIKE_INVALID_VALUE;
|
|
}
|
|
|
|
cert_data = ipike_payload_certificate_data(payload);
|
|
cert_data_len = ipike_payload_certificate_data_length(payload);
|
|
|
|
/* Expect a 20 byte SHA digest followed by an URL */
|
|
if ( cert_data_len <= SHA_DIGEST_LENGTH )
|
|
{
|
|
IPCOM_LOG1(ERR,
|
|
"ipike_cert_extract: Invalid length of \"Hash And URL\" data (type %d)",
|
|
cert_data_len);
|
|
return IPIKE_INVALID_VALUE;
|
|
}
|
|
|
|
/* Verify that the URL is NULL terminated */
|
|
if ( cert_data[cert_data_len - 1] != '\0' )
|
|
{
|
|
IPCOM_LOG0(ERR, "ipike_cert_extract: Invalid URL received in \"Hash And URL\" data") ;
|
|
return IPIKE_INVALID_VALUE;
|
|
}
|
|
|
|
cert->peer_url = ipcom_strdup( (char *) cert_data + SHA_DIGEST_LENGTH);
|
|
cert->peer = IP_NULL;
|
|
cert->ca = IP_NULL;
|
|
|
|
break;
|
|
}
|
|
#endif
|
|
|
|
#ifdef IPIKE_USE_OCSP
|
|
case IPIKE_OCSP_CONTENT:
|
|
cert_data = (unsigned char*)ipike_payload_certificate_data(payload);
|
|
ocsp_resp = d2i_OCSP_RESPONSE(IP_NULL, (const unsigned char**)&cert_data, ipike_payload_certificate_data_length(payload));
|
|
|
|
if (IP_NULL == ocsp_resp)
|
|
{
|
|
IPCOM_LOG1(CRIT,
|
|
"ipike_payload_certificate_extract: failed to decode the ocsp_response (type %s)",
|
|
ipike_payload_certificate_encode_type_to_string(payload->cert_encoding));
|
|
return IPIKE_INVALID_VALUE;
|
|
}
|
|
else
|
|
{
|
|
if (IP_NULL != cert->resp_peer)
|
|
OCSP_RESPONSE_free(cert->resp_peer);
|
|
cert->resp_peer = ocsp_resp;
|
|
}
|
|
break;
|
|
#endif /* IPIKE_USE_OCSP */
|
|
|
|
default:
|
|
IPCOM_LOG1(CRIT,
|
|
"ipike_payload_certificate_extract: %s not supported",
|
|
ipike_payload_certificate_encode_type_to_string(payload->cert_encoding));
|
|
return IPIKE_INVALID_VALUE;
|
|
}
|
|
|
|
return IPIKE_SUCCESS;
|
|
}
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipike_payload_certificate_req_extract_v1
|
|
*===========================================================================
|
|
*/
|
|
IP_GLOBAL Ipike_error
|
|
ipike_payload_certificate_req_extract_v1(
|
|
Ipike_cert_req_payload *payload,
|
|
Ipike_cert *cert)
|
|
{
|
|
Ip_u8 *payload_data = IP_NULL;
|
|
Ip_size_t payload_len = 0;
|
|
|
|
payload_data = ipike_payload_certificate_req_data(payload);
|
|
payload_len = ipike_payload_certificate_req_data_length(payload);
|
|
|
|
/* It's valid for a peer to send an empty certificate request payload.
|
|
* See RFC4945 Section 3.2.7.2. */
|
|
if ( payload_len == 0 )
|
|
{
|
|
IPCOM_LOG0(DEBUG2, "ipike_payload_certificate_req_extract_v1() ::"\
|
|
" received empty certificate request payload");
|
|
return IPIKE_SUCCESS;
|
|
}
|
|
|
|
switch (payload->cert_encoding)
|
|
{
|
|
case IPIKE_CERT_X509_SIGNATURE:
|
|
{
|
|
/* Get preferred CA certificate to use. This information could be used
|
|
to separate tunnels by the CA certificate. This is not supported so
|
|
just accept the presence of this payload for now. In IKEv1 this
|
|
payload includes a DER encoded subject name of a CA which is
|
|
trusted by the peer */
|
|
X509_NAME *x509_name = IP_NULL;
|
|
|
|
x509_name = d2i_X509_NAME(IP_NULL,
|
|
(const unsigned char **)&payload_data,
|
|
(long)payload_len);
|
|
|
|
if ( !x509_name )
|
|
{
|
|
IPCOM_LOG0(ERR,
|
|
"ipike_payload_certificate_req_extract_v1() ::"\
|
|
" invalid CA format");
|
|
return IPIKE_ISAKMP_INVALID_CERT_AUTHORITY;
|
|
}
|
|
|
|
/* Find CA based on name, do nothing for now */
|
|
IPCOM_UNUSED_ARG(cert);
|
|
|
|
X509_NAME_free(x509_name);
|
|
break;
|
|
}
|
|
default:
|
|
IPCOM_LOG1(CRIT,
|
|
"ipike_payload_certificate_req_extract: %s encoding not supported",
|
|
ipike_payload_certificate_encode_type_to_string(payload->cert_encoding));
|
|
return IPIKE_ISAKMP_INVALID_CERT_ENCODING;
|
|
}
|
|
|
|
return IPIKE_SUCCESS;
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipike_payload_certificate_req_extract_v2
|
|
*===========================================================================
|
|
*/
|
|
#ifdef IPIKE_USE_OCSP
|
|
IP_GLOBAL Ipike_error
|
|
ipike_payload_certificate_req_extract_v2(
|
|
Ipike_cert_req_payload* payload,
|
|
Ip_bool* ocsp_resp_flag)
|
|
{
|
|
*ocsp_resp_flag = IP_FALSE;
|
|
|
|
switch (payload->cert_encoding)
|
|
{
|
|
case IPIKE_OCSP_CONTENT:
|
|
IPCOM_LOG0(DEBUG2,
|
|
"ipike_payload_certificate_req_extract: Received OCSP request");
|
|
if (payload->header.length > 5)
|
|
{
|
|
/* Extract Responder public key SHA1 hashes */
|
|
#if 0
|
|
unsigned char *cert_data;
|
|
|
|
cert_data = (unsigned char*)ipike_payload_certificate_req_data(payload);
|
|
#endif
|
|
/*!!OCSP TODO: match hashes against OCSP response store
|
|
to select one of the many. Currently only OCSP
|
|
responses signed by CA can be configured */
|
|
IPCOM_LOG0(DEBUG2,
|
|
"ipike_payload_certificate_req_extract: Ignoring SHA1 hashes in OCSP content");
|
|
|
|
IPCOM_LOG0(DEBUG2,
|
|
"ipike_payload_certificate_req_extract: Only support CA signed OCSP responses");
|
|
}
|
|
*ocsp_resp_flag = IP_TRUE;
|
|
break;
|
|
|
|
case IPIKE_CERT_X509_SIGNATURE:
|
|
/* Get preferred CA certificate to use. This information could be used
|
|
to separate tunnels by the CA certificate. This is not supported so
|
|
just accept the presence of this payload for now. */
|
|
break;
|
|
|
|
default:
|
|
IPCOM_LOG1(CRIT,
|
|
"ipike_payload_certificate_req_extract: %s encoding not supported",
|
|
ipike_payload_certificate_encode_type_to_string(payload->cert_encoding));
|
|
return IPIKE_INVALID_VALUE;
|
|
}
|
|
|
|
return IPIKE_SUCCESS;
|
|
}
|
|
#endif /* #ifdef IPIKE_USE_OCSP */
|
|
|
|
|
|
/*
|
|
****************************************************************************
|
|
* END OF FILE
|
|
****************************************************************************
|
|
*/
|