aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--dirmngr/http.h3
-rw-r--r--dirmngr/ks-action.c6
-rw-r--r--dirmngr/ks-engine-ldap.c486
-rw-r--r--dirmngr/ldap-parse-uri.c14
-rw-r--r--dirmngr/server.c5
-rw-r--r--doc/gpg.texi11
-rw-r--r--g10/call-dirmngr.c18
-rw-r--r--g10/getkey.c9
-rw-r--r--g10/gpgv.c11
-rw-r--r--g10/keyserver-internal.h2
-rw-r--r--g10/keyserver.c34
-rw-r--r--g10/options.h1
-rw-r--r--g10/test-stubs.c11
-rw-r--r--kbx/keybox-openpgp.c12
-rw-r--r--scd/app-openpgp.c33
-rw-r--r--scd/ccid-driver.c2
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,