Sorry,

took some time to see this one.

attached the code; the order in which certificates are parsed into cacert is important.

This is extract of setting up; All statements are needed.

if( ( ret = mbedtls_ssl_config_defaults( &conf,
MBEDTLS_SSL_IS_CLIENT,
MBEDTLS_SSL_TRANSPORT_STREAM,
MBEDTLS_SSL_PRESET_DEFAULT ) ) != 0 )
{
coap_log( LOG_ERR, " failed\n ! mbedtls_ssl_config_defaults returned %d\n\n", ret);
goto exit;
}
mbedtls_ssl_conf_authmode( &conf, MBEDTLS_SSL_VERIFY_OPTIONAL );
mbedtls_ssl_conf_ca_chain( &conf, &cacert, NULL );
mbedtls_ssl_conf_verify(&conf,
cert_verify_callback_mbedtls, &entry);
if( ( ret = mbedtls_ssl_conf_own_cert( &conf, &cacert, &pkey ) ) != 0 )
{
coap_log(LOG_ERR, " failed\n ! mbedtls_ssl_conf_own_cert returned %d\n\n",
ret );
goto exit;
}
mbedtls_ssl_conf_rng( &conf, mbedtls_ctr_drbg_random, &ctr_drbg );

mbedtls_ssl_conf_sni( &conf, sni_callback, &entry );

if( ( ret = mbedtls_ssl_setup( &ssl, &conf ) ) != 0 )
{
coap_log( LOG_ERR, " failed\n ! mbedtls_ssl_setup returned %d\n\n", ret );
goto exit;
}

if( ( ret = mbedtls_ssl_set_hostname( &ssl, CN_NAME ) ) != 0 )
{
coap_log( LOG_ERR, " failed\n ! mbedtls_ssl_set_hostname returned %d\n\n", ret );
goto exit;
}

mbedtls_ssl_set_bio( &ssl, &server_fd, mbedtls_net_send, mbedtls_net_recv, NULL );

_________________________________________________

greetings,

peter
Michael Richardson schreef op 2021-07-14 19:39:

Peter,

Can you tell us what the critical mbedtls operation was that made the SNI communication with my MASA work in the end? Just for the benefit of the
archives.

--
Michael Richardson <[email protected]>, Sandelman Software Works
-= IPv6 IoT consulting =-

_______________________________________________
Anima mailing list
[email protected]
https://www.ietf.org/mailman/listinfo/anima
/*
 *  SSL client demonstration program
 *
 *  Copyright (C) 2006-2015, ARM Limited, All Rights Reserved
 *  SPDX-License-Identifier: Apache-2.0
 *
 *  Licensed under the Apache License, Version 2.0 (the "License"); you may
 *  not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *  http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 *  WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 *
 *  This file is part of mbed TLS (https://tls.mbed.org)
 */


#include "mbedtls/config.h"

#include <stdio.h>
#include <stdlib.h>
#define mbedtls_time            time
#define mbedtls_time_t          time_t
#define mbedtls_fprintf         fprintf
#define mbedtls_printf          printf
#define mbedtls_exit            exit
#define MBEDTLS_EXIT_SUCCESS    EXIT_SUCCESS
#define MBEDTLS_EXIT_FAILURE    EXIT_FAILURE

#include "mbedtls/net_sockets.h"
#include "mbedtls/debug.h"
#include "mbedtls/ssl.h"
#include "mbedtls/entropy.h"
#include "mbedtls/ctr_drbg.h"
#include "mbedtls/error.h"
#include "mbedtls/certs.h"
#include "mbedtls/oid.h"

#include <string.h>


#ifdef __GNUC__
#define UNUSED_PARAM __attribute__ ((unused))
#else /* not a GCC */
#define UNUSED_PARAM
#endif /* GCC */

/* names of files generated beforehand */

#define CA_MASA_CRT            "./../coap_cc_code/certificates/brski/certs/ca-masa.crt"
#define MASA_SRV_CRT           "./../coap_cc_code/certificates/brski/intermediate/certs/masa_server.crt"
#define MASA_SRV_KEY           "./../coap_cc_code/certificates/brski/intermediate/private/masa_server.key"

#define CA_REGIS_CRT           "./../coap_cc_code/certificates/brski/certs/ca-regis.crt"
#define REGIS_SRV_CRT          "./../coap_cc_code/certificates/brski/intermediate/certs/regis_server.crt"
#define REGIS_SRV_KEY          "./../coap_cc_code/certificates/brski/intermediate/private/regis_server.key"

#define MASA_CLIENT_DER            "./../coap_cc_code/certificates/transport/masa/client.der"
#define MASA_SERVER_DER            "./../coap_cc_code/certificates/transport/masa/server.der"
#define REGIS_CLIENT_DER           "./../coap_cc_code/certificates/transport/registrar/client.der"
#define REGIS_SERVER_DER           "./../coap_cc_code/certificates/transport/registrar/server.der"
#define PLEDGE_CLIENT_DER          "./../coap_cc_code/certificates/transport/pledge/client.der"
#define PLEDGE_SERVER_DER          "./../coap_cc_code/certificates/transport/pledge/server.der"

#define SERVER_PORT "4433"
#define SERVER_NAME "localhost"
#define GET_REQUEST "GET / HTTP/1.0\r\n\r\n"
#define CN_NAME "MASA server"

#define DEBUG_LEVEL 0

typedef struct coap_string_t{
   uint8_t *s;
   size_t  length;
} coap_string_t;

typedef struct pki_sni_entry {
  char *sni;
  mbedtls_x509_crt *cacert;
  mbedtls_x509_crt *public_cert;
  mbedtls_pk_context *private_key;
} pki_sni_entry;

/* write_file_mem
 * write from memory contained in contents to file
 * returns ok = 0; nok = 1;
 */
uint8_t 
write_file_mem(const char* file, coap_string_t *contents) {
  FILE *f = fopen(file, "w");
  
  if (f == NULL){
      printf( "file %s cannot be opened\n", file);
	  return 1;
  }
  size_t size = fwrite( contents->s, contents->length, 1, f);
  fclose( f);
  if (size == 1)return 0;
  return 1;
}


static void my_debug( void *ctx, int level,
                      const char *file, int line,
                      const char *str )
{
    ((void) level);

    mbedtls_fprintf( (FILE *) ctx, "%s:%04d: %s", file, line, str );
    fflush(  (FILE *) ctx  );
}

char*
get_san_or_cn_from_cert(mbedtls_x509_crt *crt)
{
  if (crt) {
    mbedtls_asn1_named_data * cn_data = NULL;

    if (crt->ext_types & MBEDTLS_X509_EXT_SUBJECT_ALT_NAME) {
      mbedtls_asn1_sequence *seq = &crt->subject_alt_names;
      while (seq && seq->buf.p == NULL) {
        seq = seq->next;
      }
      if (seq) {
        // Return the Subject Alt Name 
        return strndup((const char *)seq->buf.p,
                             seq->buf.len);
      }
    }
    cn_data = mbedtls_asn1_find_named_data(&crt->subject,
                                           MBEDTLS_OID_AT_CN,
                                           MBEDTLS_OID_SIZE(MBEDTLS_OID_AT_CN));
    if (cn_data) {
//       Return the Common Name 
      return (char *)strndup((const char *)cn_data->val.p,
                             cn_data->val.len);
    }
  }
  return NULL;
}

int 
cert_verify_callback_mbedtls(void *data UNUSED_PARAM, 
                             mbedtls_x509_crt *crt,
                             int depth, 
                             uint32_t *flags UNUSED_PARAM)
{
  char *cn = get_san_or_cn_from_cert(crt);
  printf( "CN '%s' presented by client (%s)\n",
           cn, depth ? "CA" : "Certificate");

	printf(" certificate to be written to %s \n", PLEDGE_SERVER_DER);
    char file[] = PLEDGE_SERVER_DER;
    coap_string_t contents = {.length = crt->raw.len, .s = NULL};
    contents.s = malloc(crt->raw.len);
    memcpy(contents.s, crt->raw.p, crt->raw.len);
    uint8_t ok = write_file_mem(file, &contents); 
    free(contents.s); 
    if (ok != 0)printf( "certificate is not written to %s \n", PLEDGE_SERVER_DER);    
    return 0;
}

int sni_callback( void *p_info, mbedtls_ssl_context *ssl,
              const unsigned char *name, size_t name_len )
{
	 printf("\n\nsni_callback with name:  ");
	 for (uint8_t qq = 0; qq < (uint8_t)name_len; qq++)printf("%c",name[qq]);
	 printf("\n\n");
     pki_sni_entry *cur = (pki_sni_entry *)p_info;
     mbedtls_ssl_set_hs_ca_chain( ssl, cur->public_cert, NULL );     
     return( mbedtls_ssl_set_hs_own_cert( ssl, cur->public_cert, cur->private_key ) );

    /* certificate not found: return an error code */
    return( -1 );
}

int main( void )
{
    int ret = 1, len;
    int exit_code = MBEDTLS_EXIT_FAILURE;
    mbedtls_net_context server_fd;
    uint32_t flags;
    unsigned char buf[1024];
    const char *pers   = "ssl_client1";
    char ca_file_name[]     = CA_REGIS_CRT;
    char client_file_name[] = REGIS_SRV_CRT;
    char  key_file_name[]   = REGIS_SRV_KEY; 
    char  passwd[] = "watnietweet";
    pki_sni_entry entry;

    mbedtls_entropy_context entropy;
    mbedtls_ctr_drbg_context ctr_drbg;
    mbedtls_ssl_context ssl;
    mbedtls_ssl_config conf;
    mbedtls_x509_crt cacert;
    mbedtls_x509_crt cltcert;
    mbedtls_pk_context pkey;

#if defined(MBEDTLS_DEBUG_C)
    mbedtls_debug_set_threshold( DEBUG_LEVEL );
#endif

    /*
     * 0. Initialize the RNG and the session data
     */
    mbedtls_net_init( &server_fd );
    mbedtls_ssl_init( &ssl );
    mbedtls_ssl_config_init( &conf );
    mbedtls_x509_crt_init( &cacert );
    mbedtls_pk_init( &pkey );    
    mbedtls_ctr_drbg_init( &ctr_drbg );

    mbedtls_printf( "\n  . Seeding the random number generator..." );
    fflush( stdout );

    mbedtls_entropy_init( &entropy );
    if( ( ret = mbedtls_ctr_drbg_seed( &ctr_drbg, mbedtls_entropy_func, &entropy,
                               (const unsigned char *) pers,
                               strlen( pers ) ) ) != 0 )
    {
        mbedtls_printf( " failed\n  ! mbedtls_ctr_drbg_seed returned %d\n", ret );
        goto exit;
    }

    mbedtls_printf( " ok\n" );

    /*
     * 0. Initialize certificates
     */
    mbedtls_printf( "  . Loading the CA root certificate ... name %s ", ca_file_name);
    fflush( stdout );

    ret = mbedtls_x509_crt_parse_file( &cacert, ca_file_name );
    if( ret < 0 )
    {
        mbedtls_printf( " failed\n  !  mbedtls_x509_crt_parse returned -0x%x\n\n", (unsigned int) -ret );
        goto exit;
    }

    mbedtls_printf( " ok (%d skipped)\n", ret );
    
    fprintf(stderr, "loading server certificate from %s to ca_cert\n", ca_file_name);
    ret = mbedtls_x509_crt_parse_file( &cacert, ca_file_name );
    if( ret != 0 )
    {
	  coap_log( LOG_ERR, "failed\n  !  mbedtls_x509_crt_parse_file returned %d\n\n", ret );
      goto exit;
    }
    
    
        mbedtls_printf( "  . Loading the server certificate ... name %s ", client_file_name);
    fflush( stdout );

    ret = mbedtls_x509_crt_parse_file( &cltcert, client_file_name );
    if( ret < 0 )
    {
        mbedtls_printf( " failed\n  !  mbedtls_x509_crt_parse returned -0x%x\n\n", (unsigned int) -ret );
        goto exit;
    }
    printf(" ok \n");

    mbedtls_printf( "  . Loading the server key file ... name %s ...", key_file_name);
    fflush( stdout );
    ret =  mbedtls_pk_parse_keyfile( &pkey, key_file_name, passwd );
    if( ret != 0 )
    {
        mbedtls_printf( " failed\n  !  mbedtls_pk_parse_keyfile returned %d\n\n", ret );
        goto exit;
    }

    mbedtls_printf( " ok\n" );
    mbedtls_printf( " ok (%d skipped)\n", ret );

    /*
     * 1. Start the connection
     */
    mbedtls_printf( "  . Connecting to tcp/%s/%s...", SERVER_NAME, SERVER_PORT );
    fflush( stdout );

    if( ( ret = mbedtls_net_connect( &server_fd, SERVER_NAME,
                                         SERVER_PORT, MBEDTLS_NET_PROTO_TCP ) ) != 0 )
    {
        mbedtls_printf( " failed\n  ! mbedtls_net_connect returned %d\n\n", ret );
        goto exit;
    }

    mbedtls_printf( " ok\n" );

    /*
     * 2. Setup stuff
     */
    mbedtls_printf( "  . Setting up the SSL/TLS structure..." );
    fflush( stdout );

    if( ( ret = mbedtls_ssl_config_defaults( &conf,
                    MBEDTLS_SSL_IS_CLIENT,
                    MBEDTLS_SSL_TRANSPORT_STREAM,
                    MBEDTLS_SSL_PRESET_DEFAULT ) ) != 0 )
    {
        mbedtls_printf( " failed\n  ! mbedtls_ssl_config_defaults returned %d\n\n", ret );
        goto exit;
    }

    mbedtls_printf( " ok\n" );

    /* OPTIONAL is not optimal for security,
     * but makes interop easier in this simplified example */
    mbedtls_ssl_conf_authmode( &conf, MBEDTLS_SSL_VERIFY_OPTIONAL );
    mbedtls_ssl_conf_ca_chain( &conf, &cacert, NULL );
    mbedtls_ssl_conf_verify(&conf,
                          cert_verify_callback_mbedtls, &entry);
    if( ( ret = mbedtls_ssl_conf_own_cert( &conf, &cacert, &pkey ) ) != 0 )
        {
            mbedtls_printf( " failed\n  ! mbedtls_ssl_conf_own_cert returned %d\n\n",
                            ret );
            goto exit;
        }
    mbedtls_ssl_conf_rng( &conf, mbedtls_ctr_drbg_random, &ctr_drbg );
    mbedtls_ssl_conf_dbg( &conf, my_debug, stdout );
    entry.cacert = &cacert;
    entry.public_cert = &cltcert;
    entry.private_key = &pkey;
    mbedtls_ssl_conf_sni( &conf, sni_callback, &entry );

    if( ( ret = mbedtls_ssl_setup( &ssl, &conf ) ) != 0 )
    {
        mbedtls_printf( " failed\n  ! mbedtls_ssl_setup returned %d\n\n", ret );
        goto exit;
    }

    if( ( ret = mbedtls_ssl_set_hostname( &ssl, CN_NAME ) ) != 0 )
    {
        mbedtls_printf( " failed\n  ! mbedtls_ssl_set_hostname returned %d\n\n", ret );
        goto exit;
    }

    mbedtls_ssl_set_bio( &ssl, &server_fd, mbedtls_net_send, mbedtls_net_recv, NULL );

    /*
     * 4. Handshake
     */
    mbedtls_printf( "  . Performing the SSL/TLS handshake..." );
    fflush( stdout );

    while( ( ret = mbedtls_ssl_handshake( &ssl ) ) != 0 )
    {
        if( ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE )
        {
            mbedtls_printf( " failed\n  ! mbedtls_ssl_handshake returned -0x%x\n\n", (unsigned int) -ret );
            goto exit;
        }
    }

    mbedtls_printf( " ok\n" );

    /*
     * 5. Verify the server certificate
     */
    mbedtls_printf( "  . Verifying peer X.509 certificate..." );

    /* In real life, we probably want to bail out when ret != 0 */
    if( ( flags = mbedtls_ssl_get_verify_result( &ssl ) ) != 0 )
    {
        char vrfy_buf[512];

        mbedtls_printf( " failed\n" );

        mbedtls_x509_crt_verify_info( vrfy_buf, sizeof( vrfy_buf ), "  ! ", flags );

        mbedtls_printf( "%s\n", vrfy_buf );
    }
    else
        mbedtls_printf( " ok\n" );

    /*
     * 3. Write the GET request
     */
    mbedtls_printf( "  > Write to server:" );
    fflush( stdout );

    len = sprintf( (char *) buf, GET_REQUEST );

    while( ( ret = mbedtls_ssl_write( &ssl, buf, len ) ) <= 0 )
    {
        if( ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE )
        {
            mbedtls_printf( " failed\n  ! mbedtls_ssl_write returned %d\n\n", ret );
            goto exit;
        }
    }

    len = ret;
    mbedtls_printf( " %d bytes written\n\n%s", len, (char *) buf );

    /*
     * 7. Read the HTTP response
     */
    mbedtls_printf( "  < Read from server:" );
    fflush( stdout );

    do
    {
        len = sizeof( buf ) - 1;
        memset( buf, 0, sizeof( buf ) );
        ret = mbedtls_ssl_read( &ssl, buf, len );

        if( ret == MBEDTLS_ERR_SSL_WANT_READ || ret == MBEDTLS_ERR_SSL_WANT_WRITE )
            continue;

        if( ret == MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY )
            break;

        if( ret < 0 )
        {
            mbedtls_printf( "failed\n  ! mbedtls_ssl_read returned %d\n\n", ret );
            break;
        }

        if( ret == 0 )
        {
            mbedtls_printf( "\n\nEOF\n\n" );
            break;
        }

        len = ret;
        mbedtls_printf( " %d bytes read\n\n%s", len, (char *) buf );
    }
    while( 1 );

    mbedtls_ssl_close_notify( &ssl );

    exit_code = MBEDTLS_EXIT_SUCCESS;

exit:

#ifdef MBEDTLS_ERROR_C
    if( exit_code != MBEDTLS_EXIT_SUCCESS )
    {
        char error_buf[100];
        mbedtls_strerror( ret, error_buf, 100 );
        mbedtls_printf("Last error was: %d - %s\n\n", ret, error_buf );
    }
#endif

    mbedtls_net_free( &server_fd );

    mbedtls_x509_crt_free( &cacert );
    mbedtls_x509_crt_free( &cltcert );    
    mbedtls_pk_free( &pkey);
    mbedtls_ssl_free( &ssl );
    mbedtls_ssl_config_free( &conf );
    mbedtls_ctr_drbg_free( &ctr_drbg );
    mbedtls_entropy_free( &entropy );

#if defined(_WIN32)
    mbedtls_printf( "  + Press Enter to exit this program.\n" );
    fflush( stdout ); getchar();
#endif

    mbedtls_exit( exit_code );
}
_______________________________________________
Anima mailing list
[email protected]
https://www.ietf.org/mailman/listinfo/anima

Reply via email to