diff options
author | Tom Vrancken <dev@tomvrancken.nl> | 2019-08-26 17:12:40 +0200 |
---|---|---|
committer | Tom Vrancken <dev@tomvrancken.nl> | 2019-10-04 23:33:16 +0200 |
commit | 1bdcceac380cbfe4fa78b3dd3dc3513663fab972 (patch) | |
tree | f3005c8af7f25b22986e1041b64184f248ec9267 /src | |
parent | 5d64441a3f73379c93b65efe69e6e31e830c2d30 (diff) | |
download | gnutls-1bdcceac380cbfe4fa78b3dd3dc3513663fab972.tar.gz |
Implemented raw public key support for gnutls-cli application.
Signed-off-by: Tom Vrancken <dev@tomvrancken.nl>
Diffstat (limited to 'src')
-rw-r--r-- | src/cli-args.def | 49 | ||||
-rw-r--r-- | src/cli.c | 172 | ||||
-rw-r--r-- | src/common.c | 55 |
3 files changed, 223 insertions, 53 deletions
diff --git a/src/cli-args.def b/src/cli-args.def index 621de61f3c..602eaf9058 100644 --- a/src/cli-args.def +++ b/src/cli-args.def @@ -239,6 +239,31 @@ flag = { }; flag = { + name = rawpkkeyfile; + arg-type = string; + descrip = "Private key file (PKCS #8 or PKCS #12) or PKCS #11 URL to use"; + doc = "In order to instruct the application to negotiate raw public keys one +must enable the respective certificate types via the priority strings (i.e. CTYPE-CLI-* +and CTYPE-SRV-* flags). + +Check the GnuTLS manual on section ``Priority strings'' for more +information on how to set certificate types."; +}; + +flag = { + name = rawpkfile; + arg-type = string; + descrip = "Raw public-key file to use"; + doc = "In order to instruct the application to negotiate raw public keys one +must enable the respective certificate types via the priority strings (i.e. CTYPE-CLI-* +and CTYPE-SRV-* flags). + +Check the GnuTLS manual on section ``Priority strings'' for more +information on how to set certificate types."; + flags-must = rawpkkeyfile; +}; + +flag = { name = srpusername; arg-type = string; descrip = "SRP username to use"; @@ -467,7 +492,29 @@ Connecting to '127.0.0.1:5556'... - Simple Client Mode: @end example -By keeping the --pskusername parameter and removing the --pskkey parameter, it will query only for the password during the handshake. +By keeping the --pskusername parameter and removing the --pskkey parameter, it will query only for the password during the handshake. + +@subheading Connecting using raw public-key authentication +To connect to a server using raw public-key authentication, you need to enable the option to negotiate raw public-keys via the priority strings such as in the example below. +@example +$ ./gnutls-cli -p 5556 localhost --priority NORMAL:-CTYPE-CLI-ALL:+CTYPE-CLI-RAWPK \ + --rawpkkeyfile cli.key.pem \ + --rawpkfile cli.rawpk.pem +Processed 1 client raw public key pair... +Resolving 'localhost'... +Connecting to '127.0.0.1:5556'... +- Successfully sent 1 certificate(s) to server. +- Server has requested a certificate. +- Certificate type: X.509 +- Got a certificate list of 1 certificates. +- Certificate[0] info: + - skipped +- Description: (TLS1.3-Raw Public Key-X.509)-(ECDHE-SECP256R1)-(RSA-PSS-RSAE-SHA256)-(AES-256-GCM) +- Options: +- Handshake was completed + +- Simple Client Mode: +@end example @subheading Connecting to STARTTLS services @@ -95,9 +95,11 @@ const char *x509_certfile = NULL; const char *x509_cafile = NULL; const char *x509_crlfile = NULL; static int x509ctype; +const char *rawpk_keyfile = NULL; +const char *rawpk_file = NULL; static int disable_extensions; static int disable_sni; -static unsigned int init_flags = GNUTLS_CLIENT; +static unsigned int init_flags = GNUTLS_CLIENT | GNUTLS_ENABLE_RAWPK; static const char *priorities = NULL; static const char *inline_commands_prefix; @@ -121,10 +123,60 @@ static int cert_verify_ocsp(gnutls_session_t session); static unsigned int x509_crt_size; static gnutls_pcert_st x509_crt[MAX_CRT]; static gnutls_privkey_t x509_key = NULL; +static gnutls_pcert_st rawpk; +static gnutls_privkey_t rawpk_key = NULL; -/* Load the certificate and the private key. + +/* Load a PKCS #8, PKCS #12 private key or PKCS #11 URL */ -static void load_keys(void) +static void load_priv_key(gnutls_privkey_t* privkey, const char* key_source) +{ + int ret; + gnutls_datum_t data = { NULL, 0 }; + + ret = gnutls_privkey_init(privkey); + + if (ret < 0) { + fprintf(stderr, "*** Error initializing key: %s\n", + gnutls_strerror(ret)); + exit(1); + } + + gnutls_privkey_set_pin_function(*privkey, pin_callback, + NULL); + + if (gnutls_url_is_supported(key_source) != 0) { + ret = gnutls_privkey_import_url(*privkey, key_source, 0); + if (ret < 0) { + fprintf(stderr, + "*** Error loading url: %s\n", + gnutls_strerror(ret)); + exit(1); + } + } else { + ret = gnutls_load_file(key_source, &data); + if (ret < 0) { + fprintf(stderr, + "*** Error loading key file.\n"); + exit(1); + } + + ret = gnutls_privkey_import_x509_raw(*privkey, &data, + x509ctype, NULL, 0); + if (ret < 0) { + fprintf(stderr, + "*** Error importing key: %s\n", + gnutls_strerror(ret)); + exit(1); + } + + gnutls_free(data.data); + } +} + +/* Load the X509 certificate and the private key. + */ +static void load_x509_keys(void) { unsigned int crt_num; int ret; @@ -209,51 +261,45 @@ static void load_keys(void) gnutls_free(data.data); - ret = gnutls_privkey_init(&x509_key); + load_priv_key(&x509_key, x509_keyfile); + + fprintf(stdout, + "Processed %d client X.509 certificates...\n", + x509_crt_size); + } +} + +/* Load the raw public key and corresponding private key. + */ +static void load_rawpk_keys(void) +{ + int ret; + gnutls_datum_t data = { NULL, 0 }; + + if (rawpk_file != NULL && rawpk_keyfile != NULL) { + // First we load the raw public key + ret = gnutls_load_file(rawpk_file, &data); if (ret < 0) { - fprintf(stderr, "*** Error initializing key: %s\n", - gnutls_strerror(ret)); + fprintf(stderr, + "*** Error loading cert file.\n"); exit(1); } - gnutls_privkey_set_pin_function(x509_key, pin_callback, - NULL); - - if (gnutls_url_is_supported(x509_keyfile) != 0) { - ret = - gnutls_privkey_import_url(x509_key, - x509_keyfile, 0); - if (ret < 0) { - fprintf(stderr, - "*** Error loading url: %s\n", - gnutls_strerror(ret)); - exit(1); - } - } else { - ret = gnutls_load_file(x509_keyfile, &data); - if (ret < 0) { - fprintf(stderr, - "*** Error loading key file.\n"); - exit(1); - } + ret = gnutls_pcert_import_rawpk_raw(&rawpk, &data, x509ctype, 0, 0); + if (ret < 0) { + fprintf(stderr, + "*** Error importing rawpk to pcert: %s\n", + gnutls_strerror(ret)); + exit(1); + } - ret = - gnutls_privkey_import_x509_raw(x509_key, &data, - x509ctype, NULL, - 0); - if (ret < 0) { - fprintf(stderr, - "*** Error loading url: %s\n", - gnutls_strerror(ret)); - exit(1); - } + gnutls_free(data.data); - gnutls_free(data.data); - } + // Secondly, we load the private key corresponding to the raw pk + load_priv_key(&rawpk_key, rawpk_keyfile); fprintf(stdout, - "Processed %d client X.509 certificates...\n", - x509_crt_size); + "Processed %d client raw public key pair...\n", 1); } } @@ -541,23 +587,40 @@ cert_callback(gnutls_session_t session, * supported by the server. */ - cert_type = gnutls_certificate_type_get(session); + cert_type = gnutls_certificate_type_get2(session, GNUTLS_CTYPE_CLIENT); *pcert_length = 0; - if (cert_type == GNUTLS_CRT_X509) { - if (x509_crt_size > 0) { - if (x509_key != NULL) { - *pkey = x509_key; - } else { + switch (cert_type) { + case GNUTLS_CRT_X509: + if (x509_crt_size > 0) { + if (x509_key != NULL) { + *pkey = x509_key; + } else { + log_msg + (stdout, "- Could not find a suitable key to send to server\n"); + return -1; + } + + *pcert_length = x509_crt_size; + *pcert = x509_crt; + } + break; + case GNUTLS_CRT_RAWPK: + if (rawpk_key == NULL || rawpk.type != GNUTLS_CRT_RAWPK) { log_msg - (stdout, "- Could not find a suitable key to send to server\n"); + (stdout, "- Could not find a suitable key to send to server\n"); return -1; } - *pcert_length = x509_crt_size; - *pcert = x509_crt; - } + *pkey = rawpk_key; + *pcert = &rawpk; + *pcert_length = 1; + break; + default: + log_msg(stdout, "- Could not retrieve unsupported certificate type %s.\n", + gnutls_certificate_type_get_name(cert_type)); + return -1; } log_msg(stdout, "- Successfully sent %u certificate(s) to server.\n", @@ -1570,6 +1633,12 @@ static void cmd_parser(int argc, char **argv) if (HAVE_OPT(X509CERTFILE)) x509_certfile = OPT_ARG(X509CERTFILE); + if (HAVE_OPT(RAWPKKEYFILE)) + rawpk_keyfile = OPT_ARG(RAWPKKEYFILE); + + if (HAVE_OPT(RAWPKFILE)) + rawpk_file = OPT_ARG(RAWPKFILE); + if (HAVE_OPT(PSKUSERNAME)) psk_username = OPT_ARG(PSKUSERNAME); @@ -1841,7 +1910,8 @@ static void init_global_tls_stuff(void) } } - load_keys(); + load_x509_keys(); + load_rawpk_keys(); #ifdef ENABLE_SRP if (srp_username && srp_passwd) { diff --git a/src/common.c b/src/common.c index 433e31ac90..6a0c00ebaa 100644 --- a/src/common.c +++ b/src/common.c @@ -182,6 +182,56 @@ print_x509_info(gnutls_session_t session, FILE *out, int flag, int print_cert, i } } +static void +print_rawpk_info(gnutls_session_t session, FILE *out, int flag, int print_cert, int print_crt_status) +{ + gnutls_pcert_st pk_cert; + gnutls_pk_algorithm_t pk_algo; + const gnutls_datum_t *cert_list; + unsigned int cert_list_size = 0; + int ret; + + cert_list = gnutls_certificate_get_peers(session, &cert_list_size); + if (cert_list_size == 0) { + if (print_crt_status) + fprintf(stderr, "No certificates found!\n"); + return; + } + + log_msg(out, "- Certificate type: Raw Public Key\n"); + log_msg(out, "- Got %d Raw public-key(s).\n", + cert_list_size); + + + ret = gnutls_pcert_import_rawpk_raw(&pk_cert, cert_list, GNUTLS_X509_FMT_DER, 0, 0); + if (ret < 0) { + fprintf(stderr, "Decoding error: %s\n", + gnutls_strerror(ret)); + return; + } + + pk_algo = gnutls_pubkey_get_pk_algorithm(pk_cert.pubkey, NULL); + + log_msg(out, "- Raw pk info:\n"); + log_msg(out, " - PK algo: %s\n", gnutls_pk_algorithm_get_name(pk_algo)); + + if (print_cert) { + gnutls_datum_t pem; + + ret = gnutls_pubkey_export2(pk_cert.pubkey, GNUTLS_X509_FMT_PEM, &pem); + if (ret < 0) { + fprintf(stderr, "Encoding error: %s\n", + gnutls_strerror(ret)); + return; + } + + log_msg(out, "\n%s\n", (char*)pem.data); + + gnutls_free(pem.data); + } + +} + /* returns false (0) if not verified, or true (1) otherwise */ int cert_verify(gnutls_session_t session, const char *hostname, const char *purpose) @@ -543,10 +593,13 @@ void print_cert_info2(gnutls_session_t session, int verbose, FILE *out, int prin print_crt_status = 1; } - switch (gnutls_certificate_type_get(session)) { + switch (gnutls_certificate_type_get2(session, GNUTLS_CTYPE_PEERS)) { case GNUTLS_CRT_X509: print_x509_info(session, out, flag, print_cert, print_crt_status); break; + case GNUTLS_CRT_RAWPK: + print_rawpk_info(session, out, flag, print_cert, print_crt_status); + break; default: break; } |