diff options
-rw-r--r-- | dirmngr/http.h | 3 | ||||
-rw-r--r-- | dirmngr/ks-action.c | 6 | ||||
-rw-r--r-- | dirmngr/ks-engine-ldap.c | 486 | ||||
-rw-r--r-- | dirmngr/ldap-parse-uri.c | 14 | ||||
-rw-r--r-- | dirmngr/server.c | 5 | ||||
-rw-r--r-- | doc/gpg.texi | 11 | ||||
-rw-r--r-- | g10/call-dirmngr.c | 18 | ||||
-rw-r--r-- | g10/getkey.c | 9 | ||||
-rw-r--r-- | g10/gpgv.c | 11 | ||||
-rw-r--r-- | g10/keyserver-internal.h | 2 | ||||
-rw-r--r-- | g10/keyserver.c | 34 | ||||
-rw-r--r-- | g10/options.h | 1 | ||||
-rw-r--r-- | g10/test-stubs.c | 11 | ||||
-rw-r--r-- | kbx/keybox-openpgp.c | 12 | ||||
-rw-r--r-- | scd/app-openpgp.c | 33 | ||||
-rw-r--r-- | scd/ccid-driver.c | 2 |
16 files changed, 447 insertions, 211 deletions
diff --git a/dirmngr/http.h b/dirmngr/http.h index e81aef208..8b9c5b5eb 100644 --- a/dirmngr/http.h +++ b/dirmngr/http.h @@ -55,7 +55,8 @@ struct parsed_uri_s unsigned int opaque:1;/* Unknown scheme; PATH has the rest. */ unsigned int v6lit:1; /* Host was given as a literal v6 address. */ unsigned int onion:1; /* .onion address given. */ - unsigned int explicit_port :1; /* The port was explicitly specified. */ + unsigned int explicit_port:1; /* The port was explicitly specified. */ + unsigned int ad_current:1; /* Use Active Directory's current user. */ char *auth; /* username/password for basic auth. */ char *host; /* Host (converted to lowercase). */ unsigned short port; /* Port (always set if the host is set). */ diff --git a/dirmngr/ks-action.c b/dirmngr/ks-action.c index c1ecafb58..4883cf8c5 100644 --- a/dirmngr/ks-action.c +++ b/dirmngr/ks-action.c @@ -357,9 +357,9 @@ ks_action_fetch (ctrl_t ctrl, const char *url, estream_t outfp) /* Send an OpenPGP key to all keyservers. The key in {DATA,DATALEN} is expected to be in OpenPGP binary transport format. The metadata in {INFO,INFOLEN} is in colon-separated format (concretely, it is - the output of 'for x in keys sigs; do gpg --list-$x --with-colons - KEYID; done'. This function may modify DATA and INFO. If this is - a problem, then the caller should create a copy. */ + the output of 'gpg --list-keys --with-colons KEYID'). This function + may modify DATA and INFO. If this is a problem, then the caller + should create a copy. */ gpg_error_t ks_action_put (ctrl_t ctrl, uri_item_t keyservers, void *data, size_t datalen, diff --git a/dirmngr/ks-engine-ldap.c b/dirmngr/ks-engine-ldap.c index d94bd5e25..fa6b9da8c 100644 --- a/dirmngr/ks-engine-ldap.c +++ b/dirmngr/ks-engine-ldap.c @@ -1,7 +1,7 @@ /* ks-engine-ldap.c - talk to a LDAP keyserver * Copyright (C) 2001, 2002, 2004, 2005, 2006 * 2007 Free Software Foundation, Inc. - * Copyright (C) 2015 g10 Code GmbH + * Copyright (C) 2015, 2020 g10 Code GmbH * * This file is part of GnuPG. * @@ -46,9 +46,19 @@ #include "dirmngr.h" #include "misc.h" #include "../common/userids.h" +#include "../common/mbox-util.h" #include "ks-engine.h" #include "ldap-parse-uri.h" + +/* Flags with infos from the connected server. */ +#define SERVERINFO_REALLDAP 1 /* This is not the PGP keyserver. */ +#define SERVERINFO_PGPKEYV2 2 /* Needs "pgpeyV2" instead of "pgpKey" */ +#define SERVERINFO_SCHEMAV2 4 /* Version 2 of the Schema. */ +#define SERVERINFO_NTDS 8 /* Server is an Active Directory. */ + + + #ifndef HAVE_TIMEGM time_t timegm(struct tm *tm); #endif @@ -323,7 +333,8 @@ ks_ldap_help (ctrl_t ctrl, parsed_uri_t uri) *filter. It is the caller's responsibility to free *filter. *filter is only set if this function returns success (i.e., 0). */ static gpg_error_t -keyspec_to_ldap_filter (const char *keyspec, char **filter, int only_exact) +keyspec_to_ldap_filter (const char *keyspec, char **filter, int only_exact, + unsigned int serverinfo) { /* Remove search type indicator and adjust PATTERN accordingly. Note: don't include a preceding 0x when searching by keyid. */ @@ -332,6 +343,7 @@ keyspec_to_ldap_filter (const char *keyspec, char **filter, int only_exact) KEYDB_SEARCH_DESC desc; char *f = NULL; char *freeme = NULL; + char *p; gpg_error_t err = classify_user_id (keyspec, &desc, 1); if (err) @@ -351,9 +363,24 @@ keyspec_to_ldap_filter (const char *keyspec, char **filter, int only_exact) break; case KEYDB_SEARCH_MODE_MAIL: - if (! only_exact) - f = xasprintf ("(pgpUserID=*<%s>*)", - (freeme = ldap_escape_filter (desc.u.name))); + freeme = ldap_escape_filter (desc.u.name); + if (!freeme) + break; + if (*freeme == '<' && freeme[1] && freeme[2]) + { + /* Strip angle brackets. Note that it is does not + * matter whether we work on the plan or LDAP escaped + * version of the mailbox. */ + p = freeme + 1; + if (p[strlen(p)-1] == '>') + p[strlen(p)-1] = 0; + } + else + p = freeme; + if ((serverinfo & SERVERINFO_SCHEMAV2)) + f = xasprintf ("(gpgMailbox=%s)", p); + else if (!only_exact) + f = xasprintf ("(pgpUserID=*<%s>*)", p); break; case KEYDB_SEARCH_MODE_MAILSUB: @@ -379,6 +406,19 @@ keyspec_to_ldap_filter (const char *keyspec, char **filter, int only_exact) case KEYDB_SEARCH_MODE_FPR16: case KEYDB_SEARCH_MODE_FPR20: case KEYDB_SEARCH_MODE_FPR: + if ((serverinfo & SERVERINFO_SCHEMAV2)) + { + freeme = bin2hex (desc.u.fpr, 20, NULL); + if (!freeme) + return gpg_error_from_syserror (); + f = xasprintf ("(|(gpgFingerprint=%s)(gpgSubFingerprint=%s))", + freeme, freeme); + /* FIXME: For an exact search and in case of a match on + * gpgSubFingerprint we need to check that there is only one + * matching value. */ + } + break; + case KEYDB_SEARCH_MODE_ISSUER: case KEYDB_SEARCH_MODE_ISSUER_SN: case KEYDB_SEARCH_MODE_SN: @@ -429,40 +469,44 @@ keyspec_to_ldap_filter (const char *keyspec, char **filter, int only_exact) The values are returned in the passed variables. If you pass NULL, then the value won't be returned. It is the caller's responsibility to release *LDAP_CONNP with ldap_unbind and xfree - *BASEDNP and *PGPKEYATTRP. + *BASEDNP. If this function successfully interrogated the server, it returns 0. If there was an LDAP error, it returns the LDAP error code. If an error occurred, *basednp, etc., are undefined (and don't need to be freed.) + R_SERVERINFO receives information about the server. + If no LDAP error occurred, you still need to check that *basednp is valid. If it is NULL, then the server does not appear to be an - OpenPGP Keyserver. In this case, you also do not need to xfree - *pgpkeyattrp. */ + OpenPGP Keyserver. */ static int my_ldap_connect (parsed_uri_t uri, LDAP **ldap_connp, - char **basednp, char **pgpkeyattrp, int *real_ldapp) + char **basednp, unsigned int *r_serverinfo) { int err = 0; - LDAP *ldap_conn = NULL; - char *user = uri->auth; - struct uri_tuple_s *password_param = uri_query_lookup (uri, "password"); - char *password = password_param ? password_param->value : NULL; - + struct uri_tuple_s *password_param; + char *password; char *basedn = NULL; - /* Whether to look for the pgpKey or pgpKeyv2 attribute. */ - char *pgpkeyattr = "pgpKey"; - int real_ldap = 0; - log_debug ("my_ldap_connect(%s:%d/%s????%s%s%s%s%s)\n", - uri->host, uri->port, - uri->path ?: "", - uri->auth ? "bindname=" : "", uri->auth ?: "", - uri->auth && password ? "," : "", - password ? "password=" : "", password ?: ""); + *r_serverinfo = 0; + + password_param = uri_query_lookup (uri, "password"); + password = password_param ? password_param->value : NULL; + + if (opt.debug) + log_debug ("my_ldap_connect(%s:%d/%s????%s%s%s%s%s%s)\n", + uri->host, uri->port, + uri->path ? uri->path : "", + uri->auth ? "bindname=" : "", + uri->auth ? uri->auth : "", + uri->auth && password ? "," : "", + password ? "password=" : "", + password ? ">not shown<": "", + uri->ad_current? " auth=>current_user<":""); /* If the uri specifies a secure connection and we don't support TLS, then fail; don't silently revert to an insecure @@ -476,12 +520,18 @@ my_ldap_connect (parsed_uri_t uri, LDAP **ldap_connp, #endif } - ldap_conn = ldap_init (uri->host, uri->port); - if (! ldap_conn) + if (uri->ad_current) + ldap_conn = ldap_init (NULL, uri->port); + else + ldap_conn = ldap_init (uri->host, uri->port); + if (!ldap_conn) { err = gpg_err_code_from_syserror (); - log_error ("Failed to open connection to LDAP server (%s://%s:%d)\n", - uri->scheme, uri->host, uri->port); + if (uri->ad_current) + log_error ("error initializing LDAP for current user\n"); + else + log_error ("error initializing LDAP for (%s://%s:%d)\n", + uri->scheme, uri->host, uri->port); goto out; } @@ -492,7 +542,7 @@ my_ldap_connect (parsed_uri_t uri, LDAP **ldap_connp, err = ldap_set_option (ldap_conn, LDAP_OPT_PROTOCOL_VERSION, &ver); if (err != LDAP_SUCCESS) { - log_error ("gpgkeys: unable to go to LDAP 3: %s\n", + log_error ("ks-ldap: unable to go to LDAP 3: %s\n", ldap_err2string (err)); goto out; } @@ -526,7 +576,7 @@ my_ldap_connect (parsed_uri_t uri, LDAP **ldap_connp, LDAP_OPT_X_TLS_REQUIRE_CERT, &check_cert); if (err) { - log_error ("Failed to set TLS option on LDAP connection.\n"); + log_error ("error setting TLS option on LDAP connection\n"); goto out; } #else @@ -546,40 +596,58 @@ my_ldap_connect (parsed_uri_t uri, LDAP **ldap_connp, NULL, NULL); if (err) { - log_error ("Failed to connect to LDAP server with TLS.\n"); + log_error ("error connecting to LDAP server with TLS\n"); goto out; } } #endif - /* By default we don't bind as there is usually no need to. */ - if (uri->auth) + if (uri->ad_current) { - log_debug ("LDAP bind to %s, password %s\n", - user, password ? ">not shown<" : ">none<"); + if (opt.debug) + log_debug ("LDAP bind to current user via AD\n"); +#ifdef HAVE_W32_SYSTEM + err = ldap_bind_s (ldap_conn, NULL, NULL, LDAP_AUTH_NEGOTIATE); +#else + err = gpg_error (GPG_ERR_NOT_SUPPORTED); +#endif + if (err != LDAP_SUCCESS) + { + log_error ("error binding to LDAP via AD: %s\n", + ldap_err2string (err)); + goto out; + } + } + else if (uri->auth) + { + if (opt.debug) + log_debug ("LDAP bind to %s, password %s\n", + user, password ? ">not shown<" : ">none<"); err = ldap_simple_bind_s (ldap_conn, user, password); if (err != LDAP_SUCCESS) { - log_error ("Internal LDAP bind error: %s\n", - ldap_err2string (err)); + log_error ("error binding to LDAP: %s\n", ldap_err2string (err)); goto out; } } + else + { + /* By default we don't bind as there is usually no need to. */ + } if (uri->path && *uri->path) - /* User specified base DN. */ { + /* User specified base DN. */ basedn = xstrdup (uri->path); /* If the user specifies a base DN, then we know the server is a - real LDAP server. */ - real_ldap = 1; + * real LDAP server. */ + *r_serverinfo |= SERVERINFO_REALLDAP; } else - { + { /* Look for namingContexts. */ LDAPMessage *res = NULL; - /* Look for namingContexts. */ char *attr[] = { "namingContexts", NULL }; err = ldap_search_s (ldap_conn, "", LDAP_SCOPE_BASE, @@ -588,21 +656,22 @@ my_ldap_connect (parsed_uri_t uri, LDAP **ldap_connp, { char **context = ldap_get_values (ldap_conn, res, "namingContexts"); if (context) - /* We found some, so try each namingContext as the search - base and look for pgpBaseKeySpaceDN. Because we found - this, we know we're talking to a regular-ish LDAP - server and not an LDAP keyserver. */ { + /* We found some, so try each namingContext as the + * search base and look for pgpBaseKeySpaceDN. Because + * we found this, we know we're talking to a regular-ish + * LDAP server and not an LDAP keyserver. */ int i; char *attr2[] = { "pgpBaseKeySpaceDN", "pgpVersion", "pgpSoftware", NULL }; - real_ldap = 1; + *r_serverinfo |= SERVERINFO_REALLDAP; for (i = 0; context[i] && ! basedn; i++) { char **vals; LDAPMessage *si_res; + int is_gnupg = 0; { char *object = xasprintf ("cn=pgpServerInfo,%s", @@ -626,7 +695,10 @@ my_ldap_connect (parsed_uri_t uri, LDAP **ldap_connp, "pgpSoftware"); if (vals) { - log_debug ("Server: \t%s\n", vals[0]); + if (opt.debug) + log_debug ("Server: \t%s\n", vals[0]); + if (!ascii_strcasecmp (vals[0], "GnuPG")) + is_gnupg = 1; ldap_value_free (vals); } @@ -634,7 +706,20 @@ my_ldap_connect (parsed_uri_t uri, LDAP **ldap_connp, "pgpVersion"); if (vals) { - log_debug ("Version:\t%s\n", vals[0]); + if (opt.debug) + log_debug ("Version:\t%s\n", vals[0]); + if (is_gnupg) + { + char *fields[2]; + int nfields; + nfields = split_fields (vals[0], + fields, DIM(fields)); + if (nfields > 0 && atoi(fields[0]) > 1) + *r_serverinfo |= SERVERINFO_SCHEMAV2; + if (nfields > 1 + && !ascii_strcasecmp (fields[1], "ntds")) + *r_serverinfo |= SERVERINFO_NTDS; + } ldap_value_free (vals); } } @@ -652,7 +737,7 @@ my_ldap_connect (parsed_uri_t uri, LDAP **ldap_connp, else { /* We don't have an answer yet, which means the server might - be an LDAP keyserver. */ + be a PGP.com keyserver. */ char **vals; LDAPMessage *si_res = NULL; @@ -662,9 +747,9 @@ my_ldap_connect (parsed_uri_t uri, LDAP **ldap_connp, "(objectClass=*)", attr2, 0, &si_res); if (err == LDAP_SUCCESS) { - /* For the LDAP keyserver, this is always - "OU=ACTIVE,O=PGP KEYSPACE,C=US", but it might not be - in the future. */ + /* For the PGP LDAP keyserver, this is always + * "OU=ACTIVE,O=PGP KEYSPACE,C=US", but it might not be + * in the future. */ vals = ldap_get_values (ldap_conn, si_res, "baseKeySpaceDN"); if (vals) @@ -676,14 +761,16 @@ my_ldap_connect (parsed_uri_t uri, LDAP **ldap_connp, vals = ldap_get_values (ldap_conn, si_res, "software"); if (vals) { - log_debug ("ldap: Server: \t%s\n", vals[0]); + if (opt.debug) + log_debug ("ks-ldap: PGP Server: \t%s\n", vals[0]); ldap_value_free (vals); } vals = ldap_get_values (ldap_conn, si_res, "version"); if (vals) { - log_debug ("ldap: Version:\t%s\n", vals[0]); + if (opt.debug) + log_debug ("ks-ldap: PGP Server Version:\t%s\n", vals[0]); /* If the version is high enough, use the new pgpKeyV2 attribute. This design is iffy at best, @@ -692,7 +779,7 @@ my_ldap_connect (parsed_uri_t uri, LDAP **ldap_connp, keyserver vendor with a different numbering scheme. */ if (atoi (vals[0]) > 1) - pgpkeyattr = "pgpKeyV2"; + *r_serverinfo |= SERVERINFO_PGPKEYV2; ldap_value_free (vals); } @@ -708,29 +795,20 @@ my_ldap_connect (parsed_uri_t uri, LDAP **ldap_connp, } out: - if (! err) + if (!err && opt.debug) { log_debug ("ldap_conn: %p\n", ldap_conn); - log_debug ("real_ldap: %d\n", real_ldap); + log_debug ("server_type: %s\n", ((*r_serverinfo & SERVERINFO_REALLDAP) + ? "LDAP" : "PGP.com keyserver") ); log_debug ("basedn: %s\n", basedn); - log_debug ("pgpkeyattr: %s\n", pgpkeyattr); + log_debug ("pgpkeyattr: %s\n", + (*r_serverinfo & SERVERINFO_PGPKEYV2)? "pgpKeyV2":"pgpKey"); } - if (! err && real_ldapp) - *real_ldapp = real_ldap; - if (err) xfree (basedn); else { - if (pgpkeyattrp) - { - if (basedn) - *pgpkeyattrp = xstrdup (pgpkeyattr); - else - *pgpkeyattrp = NULL; - } - if (basednp) *basednp = basedn; else @@ -836,16 +914,11 @@ ks_ldap_get (ctrl_t ctrl, parsed_uri_t uri, const char *keyspec, { gpg_error_t err = 0; int ldap_err; - + unsigned int serverinfo; char *filter = NULL; - LDAP *ldap_conn = NULL; - char *basedn = NULL; - char *pgpkeyattr = NULL; - estream_t fp = NULL; - LDAPMessage *message = NULL; (void) ctrl; @@ -857,48 +930,52 @@ ks_ldap_get (ctrl_t ctrl, parsed_uri_t uri, const char *keyspec, return gpg_error (GPG_ERR_NOT_SUPPORTED); } - /* Before connecting to the server, make sure we have a sane - keyspec. If not, there is no need to establish a network - connection. */ - err = keyspec_to_ldap_filter (keyspec, &filter, 1); - if (err) - return (err); - /* Make sure we are talking to an OpenPGP LDAP server. */ - ldap_err = my_ldap_connect (uri, &ldap_conn, &basedn, &pgpkeyattr, NULL); + ldap_err = my_ldap_connect (uri, &ldap_conn, &basedn, &serverinfo); if (ldap_err || !basedn) { if (ldap_err) err = ldap_err_to_gpg_err (ldap_err); else - err = GPG_ERR_GENERAL; + err = gpg_error (GPG_ERR_GENERAL); goto out; } + /* Now that we have information about the server we can construct a + * query best suited for the capabilities of the server. */ + err = keyspec_to_ldap_filter (keyspec, &filter, 1, serverinfo); + if (err) + goto out; + + if (opt.debug) + log_debug ("ks-ldap: using filter: %s\n", filter); + { /* The ordering is significant. Specifically, "pgpcertid" needs to be the second item in the list, since everything after it may be discarded we aren't in verbose mode. */ char *attrs[] = { - pgpkeyattr, + "dummy", "pgpcertid", "pgpuserid", "pgpkeyid", "pgprevoked", "pgpdisabled", "pgpkeycreatetime", "modifytimestamp", "pgpkeysize", "pgpkeytype", NULL }; /* 1 if we want just attribute types; 0 if we want both attribute - types and values. */ + * types and values. */ int attrsonly = 0; - int count; + /* Replace "dummy". */ + attrs[0] = (serverinfo & SERVERINFO_PGPKEYV2)? "pgpKeyV2" : "pgpKey"; + ldap_err = ldap_search_s (ldap_conn, basedn, LDAP_SCOPE_SUBTREE, filter, attrs, attrsonly, &message); if (ldap_err) { err = ldap_err_to_gpg_err (ldap_err); - log_error ("gpgkeys: LDAP search error: %s\n", + log_error ("ks-ldap: LDAP search error: %s\n", ldap_err2string (ldap_err)); goto out; } @@ -906,7 +983,7 @@ ks_ldap_get (ctrl_t ctrl, parsed_uri_t uri, const char *keyspec, count = ldap_count_entries (ldap_conn, message); if (count < 1) { - log_error ("gpgkeys: key %s not found on keyserver\n", keyspec); + log_info ("ks-ldap: key %s not found on keyserver\n", keyspec); if (count == -1) err = ldap_to_gpg_err (ldap_conn); @@ -956,11 +1033,11 @@ ks_ldap_get (ctrl_t ctrl, parsed_uri_t uri, const char *keyspec, extract_keys (fp, ldap_conn, certid[0], each); - vals = ldap_get_values (ldap_conn, each, pgpkeyattr); + vals = ldap_get_values (ldap_conn, each, attrs[0]); if (! vals) { err = ldap_to_gpg_err (ldap_conn); - log_error("gpgkeys: unable to retrieve key %s " + log_error("ks-ldap: unable to retrieve key %s " "from keyserver\n", certid[0]); goto out; } @@ -1003,7 +1080,6 @@ ks_ldap_get (ctrl_t ctrl, parsed_uri_t uri, const char *keyspec, *r_fp = fp; } - xfree (pgpkeyattr); xfree (basedn); if (ldap_conn) @@ -1014,6 +1090,7 @@ ks_ldap_get (ctrl_t ctrl, parsed_uri_t uri, const char *keyspec, return err; } + /* Search the keyserver identified by URI for keys matching PATTERN. On success R_FP has an open stream to read the data. */ gpg_error_t @@ -1022,13 +1099,10 @@ ks_ldap_search (ctrl_t ctrl, parsed_uri_t uri, const char *pattern, { gpg_error_t err; int ldap_err; - + unsigned int serverinfo; char *filter = NULL; - LDAP *ldap_conn = NULL; - char *basedn = NULL; - estream_t fp = NULL; (void) ctrl; @@ -1040,18 +1114,8 @@ ks_ldap_search (ctrl_t ctrl, parsed_uri_t uri, const char *pattern, return gpg_error (GPG_ERR_NOT_SUPPORTED); } - /* Before connecting to the server, make sure we have a sane - keyspec. If not, there is no need to establish a network - connection. */ - err = keyspec_to_ldap_filter (pattern, &filter, 0); - if (err) - { - log_error ("Bad search pattern: '%s'\n", pattern); - return (err); - } - /* Make sure we are talking to an OpenPGP LDAP server. */ - ldap_err = my_ldap_connect (uri, &ldap_conn, &basedn, NULL, NULL); + ldap_err = my_ldap_connect (uri, &ldap_conn, &basedn, &serverinfo); if (ldap_err || !basedn) { if (ldap_err) @@ -1061,6 +1125,15 @@ ks_ldap_search (ctrl_t ctrl, parsed_uri_t uri, const char *pattern, goto out; } + /* Now that we have information about the server we can construct a + * query best suited for the capabilities of the server. */ + err = keyspec_to_ldap_filter (pattern, &filter, 0, serverinfo); + if (err) + { + log_error ("Bad search pattern: '%s'\n", pattern); + goto out; + } + /* Even if we have no results, we want to return a stream. */ fp = es_fopenmem(0, "rw"); if (!fp) @@ -1084,7 +1157,8 @@ ks_ldap_search (ctrl_t ctrl, parsed_uri_t uri, const char *pattern, "pgpkeysize", "pgpkeytype", NULL }; - log_debug ("SEARCH '%s' => '%s' BEGIN\n", pattern, filter); + if (opt.debug) + log_debug ("SEARCH '%s' => '%s' BEGIN\n", pattern, filter); ldap_err = ldap_search_s (ldap_conn, basedn, LDAP_SCOPE_SUBTREE, filter, attrs, 0, &res); @@ -1097,7 +1171,7 @@ ks_ldap_search (ctrl_t ctrl, parsed_uri_t uri, const char *pattern, err = ldap_err_to_gpg_err (ldap_err); log_error ("SEARCH %s FAILED %d\n", pattern, err); - log_error ("gpgkeys: LDAP search error: %s\n", + log_error ("ks-ldap: LDAP search error: %s\n", ldap_err2string (err)); goto out; } @@ -1119,10 +1193,10 @@ ks_ldap_search (ctrl_t ctrl, parsed_uri_t uri, const char *pattern, if (ldap_err == LDAP_SIZELIMIT_EXCEEDED) { if (count == 1) - log_error ("gpgkeys: search results exceeded server limit." + log_error ("ks-ldap: search results exceeded server limit." " First 1 result shown.\n"); else - log_error ("gpgkeys: search results exceeded server limit." + log_error ("ks-ldap: search results exceeded server limit." " First %d results shown.\n", count); } @@ -1274,7 +1348,8 @@ ks_ldap_search (ctrl_t ctrl, parsed_uri_t uri, const char *pattern, free_strlist (dupelist); } - log_debug ("SEARCH %s END\n", pattern); + if (opt.debug) + log_debug ("SEARCH %s END\n", pattern); out: if (err) @@ -1614,15 +1689,16 @@ uncescape (char *str) /* Given one line from an info block (`gpg --list-{keys,sigs} --with-colons KEYID'), pull it apart and fill in the modlist with - the relevant (for the LDAP schema) attributes. */ + the relevant (for the LDAP schema) attributes. EXTRACT_STATE + should initally be set to 0 by the caller. SCHEMAV2 is set if the + server supports the version 2 schema. */ static void -extract_attributes (LDAPMod ***modlist, char *line) +extract_attributes (LDAPMod ***modlist, int *extract_state, + char *line, int schemav2) { int field_count; char **fields; - char *keyid; - int is_pub, is_sub, is_uid, is_sig; /* Remove trailing whitespace */ @@ -1637,24 +1713,42 @@ extract_attributes (LDAPMod ***modlist, char *line) if (field_count < 7) goto out; - is_pub = strcasecmp ("pub", fields[0]) == 0; - is_sub = strcasecmp ("sub", fields[0]) == 0; - is_uid = strcasecmp ("uid", fields[0]) == 0; - is_sig = strcasecmp ("sig", fields[0]) == 0; + is_pub = !ascii_strcasecmp ("pub", fields[0]); + is_sub = !ascii_strcasecmp ("sub", fields[0]); + is_uid = !ascii_strcasecmp ("uid", fields[0]); + is_sig = !ascii_strcasecmp ("sig", fields[0]); + if (!ascii_strcasecmp ("fpr", fields[0])) + { + /* Special treatment for a fingerprint. */ + if (!(*extract_state & 1)) + goto out; /* Stray fingerprint line - ignore. */ + *extract_state &= ~1; + if (field_count >= 10 && schemav2) + { + if ((*extract_state & 2)) + modlist_add (modlist, "gpgFingerprint", fields[9]); + else + modlist_add (modlist, "gpgSubFingerprint", fields[9]); + } + goto out; + } + + *extract_state &= ~(1|2); + if (is_pub) + *extract_state |= (1|2); + else if (is_sub) + *extract_state |= 1; if (!is_pub && !is_sub && !is_uid && !is_sig) - /* Not a relevant line. */ - goto out; + goto out; /* Not a relevant line. */ keyid = fields[4]; if (is_uid && strlen (keyid) == 0) - /* The uid record type can have an empty keyid. */ - ; + ; /* The uid record type can have an empty keyid. */ else if (strlen (keyid) == 16 && strspn (keyid, "0123456789aAbBcCdDeEfF") == 16) - /* Otherwise, we expect exactly 16 hex characters. */ - ; + ; /* Otherwise, we expect exactly 16 hex characters. */ else { log_error ("malformed record!\n"); @@ -1733,15 +1827,12 @@ extract_attributes (LDAPMod ***modlist, char *line) { if (is_pub) { - modlist_add (modlist, "pgpCertID", keyid); - modlist_add (modlist, "pgpKeyID", &keyid[8]); + modlist_add (modlist, "pgpCertID", keyid); /* Long keyid(!) */ + modlist_add (modlist, "pgpKeyID", &keyid[8]); /* Short keyid */ } if (is_sub) - modlist_add (modlist, "pgpSubKeyID", keyid); - - if (is_sig) - modlist_add (modlist, "pgpSignerID", keyid); + modlist_add (modlist, "pgpSubKeyID", keyid); /* Long keyid(!) */ } if (is_pub) @@ -1839,25 +1930,22 @@ extract_attributes (LDAPMod ***modlist, char *line) } } - if ((is_uid || is_pub) && field_count >= 10) + if (is_uid && field_count >= 10) { char *uid = fields[9]; + char *mbox; - if (is_pub && strlen (uid) == 0) - /* When using gpg --list-keys, the uid is included. When - passed via gpg, it is not. It is important to process it - when it is present, because gpg 1 won't print a UID record - if there is only one key. */ - ; - else - { - uncescape (uid); - modlist_add (modlist, "pgpUserID", uid); - } + uncescape (uid); + modlist_add (modlist, "pgpUserID", uid); + if (schemav2 && (mbox = mailbox_from_userid (uid))) + { + modlist_add (modlist, "gpgMailbox", mbox); + xfree (mbox); + } } out: - free (fields); + xfree (fields); } /* Send the key in {KEY,KEYLEN} with the metadata {INFO,INFOLEN} to @@ -1870,16 +1958,13 @@ ks_ldap_put (ctrl_t ctrl, parsed_uri_t uri, { gpg_error_t err = 0; int ldap_err; - + unsigned int serverinfo; LDAP *ldap_conn = NULL; char *basedn = NULL; - char *pgpkeyattr = NULL; - int real_ldap; - LDAPMod **modlist = NULL; LDAPMod **addlist = NULL; - char *data_armored = NULL; + int extract_state; /* The last byte of the info block. */ const char *infoend = (const char *) info + infolen - 1; @@ -1903,8 +1988,7 @@ ks_ldap_put (ctrl_t ctrl, parsed_uri_t uri, return gpg_error (GPG_ERR_NOT_SUPPORTED); } - ldap_err = my_ldap_connect (uri, - &ldap_conn, &basedn, &pgpkeyattr, &real_ldap); + ldap_err = my_ldap_connect (uri, &ldap_conn, &basedn, &serverinfo); if (ldap_err || !basedn) { if (ldap_err) @@ -1914,22 +1998,31 @@ ks_ldap_put (ctrl_t ctrl, parsed_uri_t uri, goto out; } - if (! real_ldap) - /* We appear to have an OpenPGP Keyserver, which can unpack the key - on its own (not just a dumb LDAP server). */ + if (!(serverinfo & SERVERINFO_REALLDAP)) { - LDAPMod mod, *attrs[2]; - char *key[] = { data, NULL }; + /* We appear to have a PGP.com Keyserver, which can unpack the + * key on its own (not just a dump LDAP server). This will + * rarely be the case these days. */ + LDAPMod mod; + LDAPMod *attrs[2]; + char *key[2]; char *dn; + key[0] = data; + key[1] = NULL; memset (&mod, 0, sizeof (mod)); mod.mod_op = LDAP_MOD_ADD; - mod.mod_type = pgpkeyattr; + mod.mod_type = (serverinfo & SERVERINFO_PGPKEYV2)? "pgpKeyV2":"pgpKey"; mod.mod_values = key; attrs[0] = &mod; attrs[1] = NULL; - dn = xasprintf ("pgpCertid=virtual,%s", basedn); + dn = xtryasprintf ("pgpCertid=virtual,%s", basedn); + if (!dn) + { + err = gpg_error_from_syserror (); + goto out; + } ldap_err = ldap_add_s (ldap_conn, dn, attrs); xfree (dn); @@ -1942,7 +2035,12 @@ ks_ldap_put (ctrl_t ctrl, parsed_uri_t uri, goto out; } - modlist = xmalloc (sizeof (LDAPMod *)); + modlist = xtrymalloc (sizeof (LDAPMod *)); + if (!modlist) + { + err = gpg_error_from_syserror (); + goto out; + } *modlist = NULL; if (dump_modlist) @@ -1969,15 +2067,20 @@ ks_ldap_put (ctrl_t ctrl, parsed_uri_t uri, modlist_add (&modlist, "pgpKeyType", NULL); modlist_add (&modlist, "pgpUserID", NULL); modlist_add (&modlist, "pgpKeyCreateTime", NULL); - modlist_add (&modlist, "pgpSignerID", NULL); modlist_add (&modlist, "pgpRevoked", NULL); modlist_add (&modlist, "pgpSubKeyID", NULL); modlist_add (&modlist, "pgpKeySize", NULL); modlist_add (&modlist, "pgpKeyExpireTime", NULL); modlist_add (&modlist, "pgpCertID", NULL); + if ((serverinfo & SERVERINFO_SCHEMAV2)) + { + modlist_add (&modlist, "gpgFingerprint", NULL); + modlist_add (&modlist, "gpgSubFingerprint", NULL); + modlist_add (&modlist, "gpgMailbox", NULL); + } /* Assemble the INFO stuff into LDAP attributes */ - + extract_state = 0; while (infolen > 0) { char *temp = NULL; @@ -1995,17 +2098,18 @@ ks_ldap_put (ctrl_t ctrl, parsed_uri_t uri, *newline = '\0'; - extract_attributes (&modlist, info); + extract_attributes (&addlist, &extract_state, info, + (serverinfo & SERVERINFO_SCHEMAV2)); infolen = infolen - ((uintptr_t) newline - (uintptr_t) info + 1); info = newline + 1; /* Sanity check. */ if (! temp) - assert ((char *) info + infolen - 1 == infoend); + log_assert ((char *) info + infolen - 1 == infoend); else { - assert (infolen == -1); + log_assert (infolen == -1); xfree (temp); } } @@ -2016,7 +2120,9 @@ ks_ldap_put (ctrl_t ctrl, parsed_uri_t uri, if (err) goto out; - modlist_add (&addlist, pgpkeyattr, data_armored); + modlist_add (&addlist, + (serverinfo & SERVERINFO_PGPKEYV2)? "pgpKeyV2":"pgpKey", + data_armored); /* Now append addlist onto modlist. */ modlists_join (&modlist, addlist); @@ -2039,21 +2145,44 @@ ks_ldap_put (ctrl_t ctrl, parsed_uri_t uri, keyserver) this does NOT merge signatures, but replaces the whole key. This should make some people very happy. */ { - char **certid; + char **attrval; char *dn; - certid = modlist_lookup (modlist, "pgpCertID"); - if (/* We should have a value. */ - ! certid - /* Exactly one. */ - || !(certid[0] && !certid[1])) + if ((serverinfo & SERVERINFO_NTDS)) { - log_error ("Bad certid.\n"); - err = GPG_ERR_GENERAL; - goto out; + /* The modern way using a CN RDN with the fingerprint. This + * has the advantage that we won't have duplicate 64 bit + * keyids in the store. In particular NTDS requires the + * DN to be unique. */ + attrval = modlist_lookup (addlist, "gpgFingerprint"); + /* We should have exactly one value. */ + if (!attrval || !(attrval[0] && !attrval[1])) + { + log_error ("ks-ldap: bad gpgFingerprint provided\n"); + err = GPG_ERR_GENERAL; + goto out; + } + dn = xtryasprintf ("CN=%s,%s", attrval[0], basedn); } - - dn = xasprintf ("pgpCertID=%s,%s", certid[0], basedn); + else /* The old style way. */ + { + attrval = modlist_lookup (addlist, "pgpCertID"); + /* We should have exactly one value. */ + if (!attrval || !(attrval[0] && !attrval[1])) + { + log_error ("ks-ldap: bad pgpCertID provided\n"); + err = GPG_ERR_GENERAL; + goto out; + } + dn = xtryasprintf ("pgpCertID=%s,%s", attrval[0], basedn); + } + if (!dn) + { + err = gpg_error_from_syserror (); + goto out; + } + if (opt.debug) + log_debug ("ks-ldap: using DN: %s\n", dn); err = ldap_modify_s (ldap_conn, dn, modlist); if (err == LDAP_NO_SUCH_OBJECT) @@ -2063,7 +2192,7 @@ ks_ldap_put (ctrl_t ctrl, parsed_uri_t uri, if (err != LDAP_SUCCESS) { - log_error ("gpgkeys: error adding key to keyserver: %s\n", + log_error ("ks-ldap: error adding key to keyserver: %s\n", ldap_err2string (err)); err = ldap_err_to_gpg_err (err); } @@ -2077,7 +2206,6 @@ ks_ldap_put (ctrl_t ctrl, parsed_uri_t uri, ldap_unbind (ldap_conn); xfree (basedn); - xfree (pgpkeyattr); modlist_free (modlist); xfree (addlist); diff --git a/dirmngr/ldap-parse-uri.c b/dirmngr/ldap-parse-uri.c index cae0351d4..4d9272cc0 100644 --- a/dirmngr/ldap-parse-uri.c +++ b/dirmngr/ldap-parse-uri.c @@ -176,9 +176,21 @@ ldap_parse_uri (parsed_uri_t *purip, const char *uri) puri->query->valuelen = strlen (password) + 1; } - puri->use_tls = strcmp (puri->scheme, "ldaps") == 0; + puri->use_tls = !strcmp (puri->scheme, "ldaps"); puri->port = lud->lud_port; + /* On Windows detect whether this is ldap:// or ldaps:// to indicate + * that authentication via AD and the current user is requested. */ + puri->ad_current = 0; +#ifdef HAVE_W32_SYSTEM + if ((!puri->host || !*puri->host) + && (!puri->path || !*puri->path) + && (!puri->auth || !*puri->auth) + && !password + ) + puri->ad_current = 1; +#endif + out: if (lud) ldap_free_urldesc (lud); diff --git a/dirmngr/server.c b/dirmngr/server.c index 407863330..6c72e5ce1 100644 --- a/dirmngr/server.c +++ b/dirmngr/server.c @@ -2526,7 +2526,7 @@ static const char hlp_ks_put[] = " INQUIRE KEYBLOCK_INFO\n" "\n" "The client shall respond with a colon delimited info lines (the output\n" - "of 'for x in keys sigs; do gpg --list-$x --with-colons KEYID; done').\n"; + "of 'gpg --list-keys --with-colons KEYID').\n"; static gpg_error_t cmd_ks_put (assuan_context_t ctx, char *line) { @@ -2559,8 +2559,7 @@ cmd_ks_put (assuan_context_t ctx, char *line) goto leave; } - /* Ask for the key meta data. Not actually needed for HKP servers - but we do it anyway to test the client implementation. */ + /* Ask for the key meta data. */ err = assuan_inquire (ctx, "KEYBLOCK_INFO", &info, &infolen, MAX_KEYBLOCK_LENGTH); if (err) diff --git a/doc/gpg.texi b/doc/gpg.texi index fc8539cd6..7b603d7da 100644 --- a/doc/gpg.texi +++ b/doc/gpg.texi @@ -1806,6 +1806,9 @@ list. The default is "local,wkd". keyservers to use. If this fails, attempt to locate the key using the PGP Universal method of checking @samp{ldap://keys.(thedomain)}. + @item ntds + Locate the key using the Active Directory (Windows only). + @item keyserver Locate a key using a keyserver. @@ -4207,6 +4210,11 @@ for @samp{Subkey-Type}. @item Key-Length: @var{nbits} The requested length of the generated key in bits. The default is returned by running the command @samp{@gpgname --gpgconf-list}. +For ECC keys this parameter is ignored. + +@item Key-Curve: @var{curve} +The requested elliptic curve of the generated key. This is a required +parameter for ECC keys. It is ignored for non-ECC keys. @item Key-Grip: @var{hexstring} This is optional and used to generate a CSR or certificate for an @@ -4231,6 +4239,9 @@ can be handled. See also @samp{Key-Type} above. Length of the secondary key (subkey) in bits. The default is returned by running the command @samp{@gpgname --gpgconf-list}. +@item Subkey-Curve: @var{curve} +Key curve for a subkey; similar to @samp{Key-Curve}. + @item Subkey-Usage: @var{usage-list} Key usage lists for a subkey; similar to @samp{Key-Usage}. diff --git a/g10/call-dirmngr.c b/g10/call-dirmngr.c index 06403317b..1b091bde2 100644 --- a/g10/call-dirmngr.c +++ b/g10/call-dirmngr.c @@ -963,6 +963,7 @@ ks_put_inq_cb (void *opaque, const char *line) { kbnode_t node; estream_t fp; + char hexfpr[2*MAX_FINGERPRINT_LEN+1]; /* Parse the keyblock and send info lines back to the server. */ fp = es_fopenmem (0, "rw,samethread"); @@ -1020,6 +1021,8 @@ ks_put_inq_cb (void *opaque, const char *line) nbits_from_pk (pk), pk->pubkey_algo, pk->keyid, pk->timestamp, pk->expiredate, NULL); + es_fprintf (fp, "fpr:::::::::%s:\n", + hexfingerprint (pk, hexfpr, sizeof hexfpr)); } break; @@ -1047,21 +1050,6 @@ ks_put_inq_cb (void *opaque, const char *line) } break; - /* This bit is really for the benefit of people who - store their keys in LDAP servers. It makes it easy - to do queries for things like "all keys signed by - Isabella". */ - case PKT_SIGNATURE: - { - PKT_signature *sig = node->pkt->pkt.signature; - - if (IS_UID_SIG (sig)) - record_output (fp, node->pkt->pkttype, NULL, - -1, -1, sig->keyid, - sig->timestamp, sig->expiredate, NULL); - } - break; - default: continue; } diff --git a/g10/getkey.c b/g10/getkey.c index 3f0a6922d..e758b43de 100644 --- a/g10/getkey.c +++ b/g10/getkey.c @@ -1202,6 +1202,13 @@ get_pubkey_byname (ctrl_t ctrl, enum get_pubkey_modes mode, glo_ctrl.in_auto_key_retrieve--; break; + case AKL_NTDS: + mechanism_string = "NTDS"; + glo_ctrl.in_auto_key_retrieve++; + rc = keyserver_import_ntds (ctrl, name, &fpr, &fpr_len); + glo_ctrl.in_auto_key_retrieve--; + break; + case AKL_KEYSERVER: /* Strictly speaking, we don't need to only use a valid * mailbox for the getname search, but it helps cut down @@ -4194,6 +4201,8 @@ parse_auto_key_locate (const char *options_arg) akl->type = AKL_DANE; else if (ascii_strcasecmp (tok, "wkd") == 0) akl->type = AKL_WKD; + else if (ascii_strcasecmp (tok, "ntds") == 0) + akl->type = AKL_NTDS; else if ((akl->spec = parse_keyserver_uri (tok, 1))) akl->type = AKL_SPEC; else diff --git a/g10/gpgv.c b/g10/gpgv.c index 6b9c88d40..ac4b1feb7 100644 --- a/g10/gpgv.c +++ b/g10/gpgv.c @@ -476,6 +476,17 @@ keyserver_import_name (const char *name,struct keyserver_spec *spec) } int +keyserver_import_ntds (ctrl_t ctrl, const char *mbox, + unsigned char **fpr, size_t *fprlen) +{ + (void)ctrl; + (void)mbox; + (void)fpr; + (void)fprlen; + return -1; +} + +int keyserver_import_ldap (const char *name) { (void)name; diff --git a/g10/keyserver-internal.h b/g10/keyserver-internal.h index 46a1e1d9f..f5f7f3620 100644 --- a/g10/keyserver-internal.h +++ b/g10/keyserver-internal.h @@ -47,6 +47,8 @@ gpg_error_t keyserver_import_pka (ctrl_t ctrl, const char *name, unsigned char **fpr,size_t *fpr_len); gpg_error_t keyserver_import_wkd (ctrl_t ctrl, const char *name, int quick, unsigned char **fpr, size_t *fpr_len); +int keyserver_import_ntds (ctrl_t ctrl, const char *name, + unsigned char **fpr,size_t *fpr_len); int keyserver_import_name (ctrl_t ctrl, const char *name,unsigned char **fpr,size_t *fpr_len, struct keyserver_spec *keyserver); diff --git a/g10/keyserver.c b/g10/keyserver.c index f171b9606..b0f52fa82 100644 --- a/g10/keyserver.c +++ b/g10/keyserver.c @@ -1159,6 +1159,21 @@ keyserver_import_name (ctrl_t ctrl, const char *name, } +/* Import the keys that match exactly MBOX */ +int +keyserver_import_ntds (ctrl_t ctrl, const char *mbox, + unsigned char **fpr, size_t *fprlen) +{ + KEYDB_SEARCH_DESC desc = { 0 }; + struct keyserver_spec keyserver = { NULL, "ldap:///" }; + + desc.mode = KEYDB_SEARCH_MODE_MAIL; + desc.u.name = mbox; + + return keyserver_get (ctrl, &desc, 1, &keyserver, 0, fpr, fprlen); +} + + int keyserver_import_fprint (ctrl_t ctrl, const byte *fprint,size_t fprint_len, struct keyserver_spec *keyserver, int quick) @@ -1690,6 +1705,25 @@ keyserver_get_chunk (ctrl_t ctrl, KEYDB_SEARCH_DESC *desc, int ndesc, quiet = 1; } } + else if(desc[idx].mode == KEYDB_SEARCH_MODE_MAIL) + { + n = 1 + strlen (desc[idx].u.name) + 1 + 1; + if (idx && linelen + n > MAX_KS_GET_LINELEN) + break; /* Declare end of this chunk. */ + linelen += n; + + if (desc[idx].u.name[0] == '<') + pattern[npat] = xtrystrdup (desc[idx].u.name); + else + pattern[npat] = strconcat ("<", desc[idx].u.name, ">", NULL); + if (!pattern[npat]) + err = gpg_error_from_syserror (); + else + { + npat++; + quiet = 1; + } + } else if (desc[idx].mode == KEYDB_SEARCH_MODE_NONE) continue; else diff --git a/g10/options.h b/g10/options.h index 352c61275..3514a60dd 100644 --- a/g10/options.h +++ b/g10/options.h @@ -255,6 +255,7 @@ struct AKL_DANE, AKL_WKD, AKL_LDAP, + AKL_NTDS, AKL_KEYSERVER, AKL_SPEC } type; diff --git a/g10/test-stubs.c b/g10/test-stubs.c index 0ea9379c6..d09596ca2 100644 --- a/g10/test-stubs.c +++ b/g10/test-stubs.c @@ -234,6 +234,17 @@ keyserver_import_name (const char *name,struct keyserver_spec *spec) } int +keyserver_import_ntds (ctrl_t ctrl, const char *mbox, + unsigned char **fpr, size_t *fprlen) +{ + (void)ctrl; + (void)mbox; + (void)fpr; + (void)fprlen; + return -1; +} + +int keyserver_import_ldap (const char *name) { (void)name; diff --git a/kbx/keybox-openpgp.c b/kbx/keybox-openpgp.c index 6d6ed77dc..8ded6839c 100644 --- a/kbx/keybox-openpgp.c +++ b/kbx/keybox-openpgp.c @@ -240,8 +240,16 @@ keygrip_from_keyparm (int algo, struct keyparm_s *kp, unsigned char *grip) if (!err && !gcry_pk_get_keygrip (s_pkey, grip)) { - log_info ("kbx: error computing keygrip\n"); - err = gpg_error (GPG_ERR_GENERAL); + /* Some Linux distributions remove certain curves from Libgcrypt + * but not from GnuPG and thus the keygrip can't be computed. + * Emit a better error message for this case. */ + if (!gcry_pk_get_curve (s_pkey, 0, NULL)) + err = gpg_error (GPG_ERR_UNKNOWN_CURVE); + else + { + log_info ("kbx: error computing keygrip\n"); + err = gpg_error (GPG_ERR_GENERAL); + } } gcry_sexp_release (s_pkey); diff --git a/scd/app-openpgp.c b/scd/app-openpgp.c index 7480f5041..87d77a15b 100644 --- a/scd/app-openpgp.c +++ b/scd/app-openpgp.c @@ -3254,6 +3254,7 @@ build_privkey_template (app_t app, int keyno, static gpg_error_t build_ecc_privkey_template (app_t app, int keyno, const unsigned char *ecc_d, size_t ecc_d_len, + size_t ecc_d_fixed_len, const unsigned char *ecc_q, size_t ecc_q_len, unsigned char **result, size_t *resultlen) { @@ -3269,6 +3270,18 @@ build_ecc_privkey_template (app_t app, int keyno, size_t template_size; int pubkey_required; + /* This case doesn't occur in GnuPG 2.3 or later, because + agent/sexp-secret.c does the fixup. */ + if (ecc_d_fixed_len < ecc_d_len) + { + if (ecc_d_fixed_len != ecc_d_len - 1 || *ecc_d) + return gpg_error (GPG_ERR_INV_OBJ); + + /* Remove the additional zero. */ + ecc_d_len--; + ecc_d++; + } + pubkey_required = !!(app->app_local->keyattr[keyno].ecc.flags & ECC_FLAG_PUBKEY); @@ -3279,8 +3292,8 @@ build_ecc_privkey_template (app_t app, int keyno, datalen = 0; tp = privkey; - tp += add_tlv (tp, 0x92, ecc_d_len); - datalen += ecc_d_len; + tp += add_tlv (tp, 0x92, ecc_d_fixed_len); + datalen += ecc_d_fixed_len; if (pubkey_required) { @@ -3323,8 +3336,14 @@ build_ecc_privkey_template (app_t app, int keyno, memcpy (tp, suffix, suffix_len); tp += suffix_len; - memcpy (tp, ecc_d, ecc_d_len); - tp += ecc_d_len; + if (ecc_d_fixed_len > ecc_d_len) + { + memset (tp, 0, ecc_d_fixed_len - ecc_d_len); + memcpy (tp + ecc_d_fixed_len - ecc_d_len, ecc_d, ecc_d_len); + } + else + memcpy (tp, ecc_d, ecc_d_len); + tp += ecc_d_fixed_len; if (pubkey_required) { @@ -3843,6 +3862,7 @@ ecc_writekey (app_t app, gpg_error_t (*pincb)(void*, const char *, char **), unsigned int n; size_t oid_len; unsigned char fprbuf[20]; + size_t ecc_d_fixed_len; /* (private-key(ecc(curve%s)(q%m)(d%m))(created-at%d)): curve = "NIST P-256" */ @@ -3985,7 +4005,8 @@ ecc_writekey (app_t app, gpg_error_t (*pincb)(void*, const char *, char **), else algo = PUBKEY_ALGO_ECDSA; - oidstr = openpgp_curve_to_oid (curve, NULL); + oidstr = openpgp_curve_to_oid (curve, &n); + ecc_d_fixed_len = (n+7)/8; err = openpgp_oid_from_str (oidstr, &oid); if (err) goto leave; @@ -4050,7 +4071,7 @@ ecc_writekey (app_t app, gpg_error_t (*pincb)(void*, const char *, char **), int exmode; err = build_ecc_privkey_template (app, keyno, - ecc_d, ecc_d_len, + ecc_d, ecc_d_len, ecc_d_fixed_len, ecc_q, ecc_q_len, &template, &template_len); if (err) diff --git a/scd/ccid-driver.c b/scd/ccid-driver.c index e255ace07..ddc83200b 100644 --- a/scd/ccid-driver.c +++ b/scd/ccid-driver.c @@ -1307,6 +1307,7 @@ ccid_vendor_specific_setup (ccid_driver_t handle) DEBUGOUT ("sending escape sequence to switch to a case 1 APDU\n"); send_escape_cmd (handle, (const unsigned char*)"\x80\x02\x00", 3, NULL, 0, NULL); + libusb_clear_halt (handle->idev, handle->ep_intr); } return 0; } @@ -1596,7 +1597,6 @@ ccid_setup_intr (ccid_driver_t handle) struct libusb_transfer *transfer; int err; - libusb_clear_halt (handle->idev, handle->ep_intr); transfer = libusb_alloc_transfer (0); handle->transfer = transfer; libusb_fill_interrupt_transfer (transfer, handle->idev, handle->ep_intr, |