]> git.ipfire.org Git - thirdparty/gnutls.git/commitdiff
Implemented raw public key support for gnutls-cli application.
authorTom Vrancken <dev@tomvrancken.nl>
Mon, 26 Aug 2019 15:12:40 +0000 (17:12 +0200)
committerTom Vrancken <dev@tomvrancken.nl>
Fri, 4 Oct 2019 21:33:16 +0000 (23:33 +0200)
Signed-off-by: Tom Vrancken <dev@tomvrancken.nl>
src/cli-args.def
src/cli.c
src/common.c

index 621de61f3c7d4ecd1af662d9a6fee04f65d6bec8..602eaf9058a63f016b9aadcf5f4a1474da2bd862 100644 (file)
@@ -238,6 +238,31 @@ flag = {
     flags-must = x509keyfile;
 };
 
+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;
@@ -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
 
index 691eb98c5453b52a4ba7e074ce202859d75f51be..b31f43cadbe6930c455f0ca5d37df3e6244734d1 100644 (file)
--- a/src/cli.c
+++ b/src/cli.c
@@ -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) {
index 433e31ac9016a338bc22a0436258b590c4abe362..6a0c00ebaa4b0fc1ec29bccc8c29ca914e7b5e35 100644 (file)
@@ -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;
        }