certificates keys on pkcs11 devices

Manon Goo lists at manon.de
Mon Feb 6 02:10:41 AEDT 2017


patch against tags/V_7_4_P1:



--- ssh-add.c.old	2017-02-04 00:03:34.000000000 +0100
+++ ssh-add.c	2017-02-05 15:26:40.000000000 +0100
@@ -58,6 +58,7 @@
 #include "rsa.h"
 #include "log.h"
 #include "sshkey.h"
+#include "crypto_api.h"
 #include "sshbuf.h"
 #include "authfd.h"
 #include "authfile.h"
@@ -65,6 +66,7 @@
 #include "misc.h"
 #include "ssherr.h"
 #include "digest.h"
+#include "readconf.h"

 /* argv0 */
 extern char *__progname;
@@ -93,6 +95,17 @@
 /* User has to confirm key use */
 static int confirm = 0;

+/* Flag indicating whether debug mode is on.  May be set on the command 
line. */
+int debug_flag = 1;
+int log_level = SYSLOG_LEVEL_INFO;
+
+
+/*
+ * General data structure for command line options and options configurable
+ * in configuration files.  See readconf.h.
+ */
+Options options;
+
 /* we keep a cache of one passphrase */
 static char *pass = NULL;
 static void
@@ -331,6 +344,154 @@
 }

 static int
+add_cert(int agent_fd, const char *filename)
+{
+	struct sshkey  *cert;
+	// struct sshkey  *mypubkey;
+	char *comment = NULL;
+	char  *certpath = NULL;
+	int r, ret = -1;
+	// struct sshbuf *keyblob;
+	int had_identities = 0;
+	struct ssh_identitylist *idlist;
+	size_t i;
+	int version = 2;
+    // u_char *tmp_ed25519_sk = malloc(ED25519_SK_SZ);
+
+    xasprintf(&certpath, "%s", filename);
+	if ((r = sshkey_load_public(certpath, &cert, NULL)) != 0) {
+        fatal("Failed to load certificate \"%s\": %s",
+              certpath, ssh_err(r));
+	}
+	debug2("loaded certificate %s", filename);
+
+	if ((r = ssh_fetch_identitylist(agent_fd, version,
+	    &idlist)) != 0) {
+		if (r != SSH_ERR_AGENT_NO_IDENTITIES)
+			fprintf(stderr, "error fetching identities for "
+			    "protocol %d: %s\n", version, ssh_err(r));
+	}
+
+	for (i = 0; i < idlist->nkeys; i++) {
+		had_identities = 1;
+        debug3("\n\nLooping through identitys in agent, iteration: %zd", 
i);
+        debug("Processing id \"%s\"", idlist->comments[i]);
+		if (log_level >= SYSLOG_LEVEL_DEBUG3){
+            fprintf(stderr, "Matching identity  ");
+            if ((r = sshkey_write(idlist->keys[i],
+                                  stderr)) != 0) {
+                fprintf(stderr, "sshkey_write: %s\n",
+                        ssh_err(r));
+
+                continue;
+            }
+            fprintf(stderr, "\n");
+        }
+        if (log_level >= SYSLOG_LEVEL_DEBUG3){
+            fprintf(stderr, "Against certificate ");
+            if ((r = sshkey_write(cert, stderr)) != 0) {
+                fprintf(stderr, "sshkey_write of cert: %s\n",
+                        ssh_err(r));
+            }
+            fprintf(stderr, "\n");
+        }
+
+		debug2("Type of cert: %s  \t\t\t\t Type of identity from agent: %s", 
sshkey_type(cert), sshkey_type(idlist->keys[i]) );
+
+		if (sshkey_equal_public(cert, idlist->keys[i]) ) {
+			debug2("Certificate matches identity from agent");
+
+
+            /* Graft Certificagte with private bits */
+            switch (cert->type) {
+                case KEY_RSA_CERT :
+                    /* initialize cert->rsa->iqmp,d,p,q */
+                    debug2("RSA-CERT");
+                    sshkey_add_private(cert);
+                    break;
+
+                case KEY_ED25519_CERT :
+                    debug2("ED25519-CERT");
+                    cert->ed25519_sk =  malloc(ED25519_SK_SZ);
+                    break;
+                case KEY_ECDSA_CERT:
+                    debug2("ECDSA-CERT");
+                    /* sshkey_add_private(cert); */
+                    /* don'tr know abouzt any smartcards doing ECDSA */
+                    fatal("ECDSA-CERT is not yet implemented");
+                    break;
+                case KEY_DSA_CERT:
+                    debug2("DSA-CERT");
+                    sshkey_add_private(cert);
+                    break;
+            }
+
+
+			if ((r = ssh_add_identity_constrained(agent_fd, cert, NULL,
+			    lifetime, confirm)) != 0) {
+				error("Certificate %s (%s) add failed: %s", certpath,
+				    cert->cert->key_id, ssh_err(r));
+				goto out;
+			}
+			fprintf(stderr, "Certificate added: %s (%s)\n", certpath,
+			    cert->cert->key_id);
+            ret = 0;
+			if (lifetime != 0)
+				fprintf(stderr, "Lifetime set to %d seconds\n", lifetime);
+			if (confirm != 0)
+				fprintf(stderr, "The user must confirm each use of the key\n");
+            /* Skip proceeing other entries*/
+            goto out;
+		} else {
+			debug("Certificate does not match key in agent");
+		}
+		
+	}
+    fprintf(stderr, "Certificate does not match any identity from 
ssh-agent, concider usimng the CertificateFile option\n");
+
+ out:
+	free(certpath);
+	free(comment);
+	sshkey_free(cert);
+    ssh_free_identitylist(idlist);
+	return ret;
+}
+
+static int
+delete_cert(int agent_fd, const char *filename)
+{
+    struct sshkey  *cert;
+    char *comment = NULL;
+    char  *certpath = NULL;
+    int r, ret = -1;
+
+
+    xasprintf(&certpath, "%s", filename);
+    if ((r = sshkey_load_public(certpath, &cert, &comment)) != 0) {
+        if (r != SSH_ERR_SYSTEM_ERROR || errno != ENOENT)
+            fatal("Failed to load certificate \"%s\": %s",
+                  certpath, ssh_err(r));
+    }
+    debug2("loaded certificate %s", filename);
+
+    /* initialize cert->rsa->iqmp,d,p,q with 0 */
+    /* sshkey_add_private(cert); */
+
+    if ((r = ssh_remove_identity(agent_fd, cert)) == 0) {
+        fprintf(stderr, "Identity removed: %s (%s)\n", certpath,
+                comment);
+        ret = 0;
+    } else
+        fprintf(stderr, "Could not remove identity \"%s\": %s\n",
+                certpath, ssh_err(r));
+
+    sshkey_free(cert);
+    free(certpath);
+    free(comment);
+    return ret;
+}
+
+static int
 update_card(int agent_fd, int add, const char *id)
 {
 	char *pin = NULL;
@@ -439,6 +600,21 @@
 	return (ret);
 }

+/* Process "-C" */
+static int
+do_cert(int agent_fd, int deleting, char *file)
+{
+	debug2("do_cert: %s", file );
+	if (deleting) {
+		if (delete_cert(agent_fd, file) == -1)
+			return -1;
+	} else {
+		if (add_cert(agent_fd, file) == -1)
+			return -1;
+	}
+	return 0;
+}
+
 static int
 do_file(int agent_fd, int deleting, int key_only, char *file)
 {
@@ -461,12 +637,14 @@
 	fprintf(stderr, "  -E hash     Specify hash algorithm used for 
fingerprints.\n");
 	fprintf(stderr, "  -L          List public key parameters of all 
identities.\n");
 	fprintf(stderr, "  -k          Load only keys and not certificates.\n");
+	fprintf(stderr, "  -C file     Use the following certificate\n");
 	fprintf(stderr, "  -c          Require confirmation to sign using 
identities\n");
 	fprintf(stderr, "  -t life     Set lifetime (in seconds) when adding 
identities.\n");
 	fprintf(stderr, "  -d          Delete identity.\n");
 	fprintf(stderr, "  -D          Delete all identities.\n");
 	fprintf(stderr, "  -x          Lock agent.\n");
 	fprintf(stderr, "  -X          Unlock agent.\n");
+	fprintf(stderr, "  -v          Verbose.\n");
 	fprintf(stderr, "  -s pkcs11   Add keys from PKCS#11 provider.\n");
 	fprintf(stderr, "  -e pkcs11   Remove keys provided by PKCS#11 
provider.\n");
 }
@@ -478,6 +656,7 @@
 	extern int optind;
 	int agent_fd;
 	char *pkcs11provider = NULL;
+	char *certificateFile = NULL;
 	int r, i, ch, deleting = 0, ret = 0, key_only = 0;
 	int xflag = 0, lflag = 0, Dflag = 0;

@@ -494,6 +673,12 @@

 	setvbuf(stdout, NULL, _IOLBF, 0);

+    /*
+     * Initialize "log" output.  Since we are the client all output
+     * goes to stderr
+     */
+    log_init(argv[0], SYSLOG_LEVEL_INFO, SYSLOG_FACILITY_USER, 1);
+
 	/* First, get a connection to the authentication agent. */
 	switch (r = ssh_get_authentication_socket(&agent_fd)) {
 	case 0:
@@ -507,7 +692,7 @@
 		exit(2);
 	}

-	while ((ch = getopt(argc, argv, "klLcdDxXE:e:s:t:")) != -1) {
+	while ((ch = getopt(argc, argv, "klLcdDvxXC:E:e:s:t:")) != -1) {
 		switch (ch) {
 		case 'E':
 			fingerprint_hash = ssh_digest_alg_by_name(optarg);
@@ -532,6 +717,9 @@
 		case 'c':
 			confirm = 1;
 			break;
+		case 'C':
+			certificateFile = optarg;
+			break;
 		case 'd':
 			deleting = 1;
 			break;
@@ -552,13 +740,22 @@
 				goto done;
 			}
 			break;
+		case 'v':
+                if (log_level == SYSLOG_LEVEL_INFO)
+                    log_level = SYSLOG_LEVEL_DEBUG1;
+                else {
+                    if (log_level >= SYSLOG_LEVEL_DEBUG1 &&
+                        log_level < SYSLOG_LEVEL_DEBUG3)
+                        log_level++;
+                }
+                break;
 		default:
 			usage();
 			ret = 1;
 			goto done;
 		}
 	}
-
+
 	if ((xflag != 0) + (lflag != 0) + (Dflag != 0) > 1)
 		fatal("Invalid combination of actions");
 	else if (xflag) {
@@ -575,12 +772,16 @@
 		goto done;
 	}

+    /* reinit */
+    log_init(argv[0], log_level, SYSLOG_FACILITY_USER, 1);
+    debug2("log level is: %s", log_level_name(log_level));
+
 	argc -= optind;
 	argv += optind;
 	if (pkcs11provider != NULL) {
 		if (update_card(agent_fd, !deleting, pkcs11provider) == -1)
 			ret = 1;
-		goto done;
+		goto addcert;
 	}
 	if (argc == 0) {
 		char buf[PATH_MAX];
@@ -615,6 +816,17 @@
 		}
 	}
 	clear_pass();
+
+addcert:
+    /* process certificate passedc by -C [file] */
+    if (certificateFile != NULL) {
+        debug("using certificate from file: %s", certificateFile);
+        if (do_cert(agent_fd, deleting, certificateFile) == -1) {
+            ret = 1;
+            goto done;
+        }
+        ret = 0;
+    }

 done:
 	ssh_close_authentication_socket(agent_fd);

--On 5 February 2017 at 16:03:20 +0100 Manon Goo <lists at manon.de> wrote:

> Hi,
>
> I created a patch that allows to add ssh User Certificates to ssh-agent
> independent from the key.
> This is useful when the private key is stored on a pkcs11 device.
>
> the patch adds an option "-C [cert_file]" to ssh-add. The patch adds
> function to ssh-add to check if a an keypair exists in ssh-agent. If a
> keypair corresponds to the public key of cert_file the certificate is
> added to the ssh-agent.
> If called with -d -C  "[cert_file]" the certificate is removed.
> I added a "-v" Option to print debug messages.
>
> usage:
>
> ssh-add -s /usr/local/lib/opensc-pkcs11.so -C  ~/.ssh/mysmartcard-cert.pub
>
> ssh-add -d  -C  ~/.ssh/mysmartcard-cert.pub
>
> ssh-add -C  ~/.ssh/mysmartcard-other-cert.pub
>
> ssh-add -d  -C mysmartcard-other-cert.pub
>
> I hope this function makes sense to you.
>
> Best wihses,
> Manon
>
>
>
> --On 28 December 2016 at 03:51:44 +0100 Manon Goo <lists at manon.de> wrote:
>
>> Hi,
>>
>> I have not found any way to use a Certificate with ssh-agent when my Key
>> is stored on a pkcs11 device. I can add my key with
>>
>> ssh-add -s /usr/local/lib/opensc-pkcs11.so
>>
>> but
>>
>> ssh-add -s /usr/local/lib/opensc-pkcs11.so ~/.ssh/mykey-cert.pub
>>
>> does not add the certificate to my agent. As far as I undestand,  in
>> ssh-add.c line 580
>>
>> 	if (pkcs11provider != NULL) {
>> 		if (update_card(agent_fd, !deleting, pkcs11provider) == -1)
>> 			ret = 1;
>> 		goto done;
>> 	}
>>
>> does not check for additional (certifcate)-files files on the command
>> line and update_card neither does.
>>
>> Is there any intention to change this?
>>
>> Thanks in alot,
>> Manon
>>
>>
>>
>>
>>
>> _______________________________________________
>> openssh-unix-dev mailing list
>> openssh-unix-dev at mindrot.org
>> https://lists.mindrot.org/mailman/listinfo/openssh-unix-dev
>
>
>
> Manon Goo
> Dembach Goo Informatik GmbH & Co. KG
> Hohenzollernring 72
> D-50672 Köln
>
> Tel.: +49 221 12095-211
> Mobil: +49 151 12222781
> Fax: +49 221 12095-220
> E-Mail:manon.goo at dg-i.net
>
> Support-Hotline: 0800 / 100 4323
>
> Amtsgericht Köln HRA 22794, USt-IdNr.: DE242 159 527
> Haftende Gesellschafterin: Dembach Goo Verwaltungsgesellschaft mbH
> Deren Geschäftsführer: Andreas Dembach, Manon Goo
> _______________________________________________
> openssh-unix-dev mailing list
> openssh-unix-dev at mindrot.org
> https://lists.mindrot.org/mailman/listinfo/openssh-unix-dev



Manon Goo
Dembach Goo Informatik GmbH & Co. KG
Hohenzollernring 72
D-50672 Köln

Tel.: +49 221 12095-211
Mobil: +49 151 12222781
Fax: +49 221 12095-220
E-Mail:manon.goo at dg-i.net

Support-Hotline: 0800 / 100 4323

Amtsgericht Köln HRA 22794, USt-IdNr.: DE242 159 527
Haftende Gesellschafterin: Dembach Goo Verwaltungsgesellschaft mbH
Deren Geschäftsführer: Andreas Dembach, Manon Goo


More information about the openssh-unix-dev mailing list