Группа :: Система/Настройка/Оборудование
Пакет: gnupg-pkcs11-scd
Главная Изменения Спек Патчи Sources Загрузить Gear Bugs and FR Repocop
Патч: gnupg-pkcs11-scd-0.9.2-gost.patch
Скачать
Скачать
gnupg-pkcs11-scd/command.c | 488 +++++++++++++++++++++++++-----------
gnupg-pkcs11-scd/common.c | 29 +++
gnupg-pkcs11-scd/common.h | 5 +
gnupg-pkcs11-scd/gnupg-pkcs11-scd.1 | 4 +-
gnupg-pkcs11-scd/keyutil.c | 347 +++++++++++++++++++------
gnupg-pkcs11-scd/keyutil.h | 29 ++-
gnupg-pkcs11-scd/scdaemon.c | 42 +++-
7 files changed, 710 insertions(+), 234 deletions(-)
diff --git a/gnupg-pkcs11-scd/command.c b/gnupg-pkcs11-scd/command.c
index 331a005..57ca2d9 100644
--- a/gnupg-pkcs11-scd/command.c
+++ b/gnupg-pkcs11-scd/command.c
@@ -422,7 +422,7 @@ send_certificate_list (
if (
(error = assuan_write_status (
ctx,
- "KEY-FRIEDNLY",
+ "KEY-FRIENDLY",
nameinfo
)) != GPG_ERR_NO_ERROR
) {
@@ -515,10 +515,6 @@ send_certificate_list (
free (nameinfo);
nameinfo = NULL;
}
-
- if (error != GPG_ERR_NO_ERROR) {
- goto cleanup;
- }
}
error = GPG_ERR_NO_ERROR;
@@ -974,6 +970,64 @@ cleanup:
return gpg_error (error);
}
+#define NSSCK_VENDOR_PKCS11_RU_TEAM 0xD4321000 /* 0x80000000 | 0x54321000 */
+#define CK_VENDOR_PKCS11_RU_TEAM_TC26 NSSCK_VENDOR_PKCS11_RU_TEAM
+
+#define CKM_GOSTR3410_KEY_PAIR_GEN 0x00001200
+#define CKM_GOSTR3410 0x00001201
+#define CKM_GOSTR3410_WITH_GOSTR3411 0x00001202
+#define CKM_GOSTR3410_KEY_WRAP 0x00001203
+#define CKM_GOSTR3410_DERIVE 0x00001204
+#define CKM_GOSTR3411 0x00001210
+#define CKM_GOSTR3411_HMAC 0x00001211
+#define CKM_GOST28147_KEY_GEN 0x00001220
+#define CKM_GOST28147_ECB 0x00001221
+#define CKM_GOST28147 0x00001222
+#define CKM_GOST28147_MAC 0x00001223
+#define CKM_GOST28147_KEY_WRAP 0x00001224
+#define CKM_GOSTR3410_512 (CK_VENDOR_PKCS11_RU_TEAM_TC26 | 0x006)
+#define CKM_GOSTR3410_12_DERIVE (CK_VENDOR_PKCS11_RU_TEAM_TC26 |0x007)
+
+static key_subtype_t
+get_key_subtype(assuan_context_t ctx,
+ pkcs11h_certificate_id_t cert_id)
+{
+ unsigned char *blob = NULL;
+ size_t blob_size;
+ gpg_err_code_t error = GPG_ERR_GENERAL;
+ cert_params_t *params = NULL;
+ key_subtype_t ret = KEY_UNKNOWN;
+
+ if (
+ (error = get_cert_blob (
+ ctx,
+ cert_id,
+ &blob,
+ &blob_size
+ )) != GPG_ERR_NO_ERROR ||
+ (error = keyutil_get_cert_params (
+ blob,
+ blob_size,
+ ¶ms
+ )) != GPG_ERR_NO_ERROR
+ ) {
+ goto cleanup;
+ }
+
+ ret = params->key_subtype;
+
+ cleanup:
+
+ keyutil_params_free (params);
+
+ if (blob != NULL) {
+ free (blob);
+ blob = NULL;
+ }
+
+ return ret;
+}
+
/** Sign data (set by SETDATA) with certificate id in line. */
gpg_error_t cmd_pksign (assuan_context_t ctx, char *line)
{
@@ -1002,12 +1056,19 @@ gpg_error_t cmd_pksign (assuan_context_t ctx, char *line)
{ 0x30, 0x51, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86,
0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03, 0x05,
0x00, 0x04, 0x40 };
+ static const unsigned char gost94_prefix[] = /* (1.2.643.2.2.3) */
+ { 0x2a, 0x85, 0x03, 0x02, 0x02, 0x03 };
+ static const unsigned char gost12_256_prefix[] = /* (1.2.643.7.1.1.3.2) */
+ { 0x2a, 0x85, 0x03, 0x07, 0x01, 0x01, 0x03, 0x02 };
+ static const unsigned char gost12_512_prefix[] = /* (1.2.643.7.1.1.3.3) */
+ { 0x2a, 0x85, 0x03, 0x07, 0x01, 0x01, 0x03, 0x03 };
gpg_err_code_t error = GPG_ERR_GENERAL;
pkcs11h_certificate_id_t cert_id = NULL;
pkcs11h_certificate_t cert = NULL;
cmd_data_t *data = (cmd_data_t *)assuan_get_pointer (ctx);
- cmd_data_t *_data = data;
+ cmd_data_t data_buf = *data;
+ cmd_data_t *_data = &data_buf;
int need_free__data = 0;
int session_locked = 0;
unsigned char *sig = NULL;
@@ -1023,6 +1084,16 @@ gpg_error_t cmd_pksign (assuan_context_t ctx, char *line)
INJECT_SHA384,
INJECT_SHA512
} inject = INJECT_NONE;
+ enum {
+ REJECT_NONE,
+ REJECT_GOST94,
+ REJECT_GOST12_256,
+ REJECT_GOST12_512
+ } reject = REJECT_NONE;
+ enum {
+ REVERSE_NONE,
+ REVERSE_BYTES
+ } reverse = REVERSE_NONE;
if (data->data == NULL) {
error = GPG_ERR_INV_DATA;
@@ -1054,6 +1125,36 @@ gpg_error_t cmd_pksign (assuan_context_t ctx, char *line)
error = GPG_ERR_INV_DATA;
goto cleanup;
}
+
+ if (
+ (error = _get_certificate_by_name (
+ ctx,
+ line,
+ OPENPGP_SIGN,
+ &cert_id,
+ NULL
+ )) != GPG_ERR_NO_ERROR
+ ) {
+ goto cleanup;
+ }
+
+ CK_MECHANISM_TYPE mech;
+ switch (get_key_subtype (ctx, cert_id)) {
+ case KEY_RSA_RSA:
+ mech = CKM_RSA_PKCS;
+ break;
+ case KEY_ECC_GOST2001:
+ case KEY_ECC_GOST2012_256:
+ mech = CKM_GOSTR3410;
+ break;
+ case KEY_ECC_GOST2012_512:
+ mech = CKM_GOSTR3410_512;
+ break;
+ default:
+ error = GPG_ERR_UNSUPPORTED_ALGORITHM;
+ goto cleanup;
+ }
+
/*
* sender prefixed data with algorithm OID
*/
@@ -1114,26 +1215,50 @@ gpg_error_t cmd_pksign (assuan_context_t ctx, char *line)
}
}
else {
- if (
- data->size == 0x10 + sizeof (md5_prefix) ||
- data->size == 0x14 + sizeof (sha1_prefix) ||
- data->size == 0x14 + sizeof (rmd160_prefix)
- ) {
+ switch (mech) {
+ case CKM_GOSTR3410:
+ case CKM_GOSTR3410_512:
+ inject = INJECT_NONE;
+ reverse = REVERSE_BYTES;
if (
- memcmp (data->data, md5_prefix, sizeof (md5_prefix)) &&
- memcmp (data->data, sha1_prefix, sizeof (sha1_prefix)) &&
- memcmp (data->data, rmd160_prefix, sizeof (rmd160_prefix))
+ 0 == memcmp (data->data, gost94_prefix,
+ sizeof (gost94_prefix))
) {
- error = GPG_ERR_UNSUPPORTED_ALGORITHM;
- goto cleanup;
+ reject = REJECT_GOST94;
+ } else if (
+ 0 == memcmp (data->data, gost12_256_prefix,
+ sizeof (gost12_256_prefix))
+ ) {
+ reject = REJECT_GOST12_256;
+ } else if (
+ 0 == memcmp (data->data, gost12_512_prefix,
+ sizeof (gost12_512_prefix))
+ ) {
+ reject = REJECT_GOST12_512;
+ }
+ break;
+ default:
+ if (
+ data->size == 0x10 + sizeof (md5_prefix) ||
+ data->size == 0x14 + sizeof (sha1_prefix) ||
+ data->size == 0x14 + sizeof (rmd160_prefix)
+ ) {
+ if (
+ memcmp (data->data, md5_prefix, sizeof (md5_prefix)) &&
+ memcmp (data->data, sha1_prefix, sizeof (sha1_prefix)) &&
+ memcmp (data->data, rmd160_prefix, sizeof (rmd160_prefix))
+ ) {
+ error = GPG_ERR_UNSUPPORTED_ALGORITHM;
+ goto cleanup;
+ }
+ }
+ else {
+ /*
+ * unknown hash algorithm;
+ * gnupg's scdaemon forces to SHA1
+ */
+ inject = INJECT_SHA1;
}
- }
- else {
- /*
- * unknown hash algorithm;
- * gnupg's scdaemon forces to SHA1
- */
- inject = INJECT_SHA1;
}
}
@@ -1174,17 +1299,12 @@ gpg_error_t cmd_pksign (assuan_context_t ctx, char *line)
goto cleanup;
}
- need_free__data = 1;
-
- if ((_data = (cmd_data_t *)malloc (sizeof (cmd_data_t))) == NULL) {
- error = GPG_ERR_ENOMEM;
- goto cleanup;
- }
-
if ((_data->data = (unsigned char *)malloc (data->size + oid_size)) == NULL) {
error = GPG_ERR_ENOMEM;
goto cleanup;
}
+
+ need_free__data = 1;
_data->size = 0;
memmove (_data->data+_data->size, oid, oid_size);
@@ -1193,17 +1313,53 @@ gpg_error_t cmd_pksign (assuan_context_t ctx, char *line)
_data->size += data->size;
}
- if (
- (error = _get_certificate_by_name (
- ctx,
- line,
- OPENPGP_SIGN,
- &cert_id,
- NULL
- )) != GPG_ERR_NO_ERROR
- ) {
- goto cleanup;
- }
+ if (reject != REJECT_NONE) {
+ size_t oid_size;
+ switch (reject) {
+ case REJECT_GOST94:
+ oid_size = sizeof(gost94_prefix);
+ break;
+ case REJECT_GOST12_256:
+ oid_size = sizeof(gost12_256_prefix);
+ break;
+ case REJECT_GOST12_512:
+ oid_size = sizeof(gost12_512_prefix);
+ break;
+ default:
+ error = GPG_ERR_INV_DATA;
+ goto cleanup;
+ }
+
+ if (need_free__data) {
+ memmove (_data->data, _data->data + oid_size,
+ _data->size - oid_size);
+ } else {
+ _data->data = _data->data + oid_size;
+ }
+ _data->size = _data->size - oid_size;
+ }
+
+ if (reverse != REVERSE_NONE) {
+ if (!need_free__data) {
+ unsigned char *src_data = _data->data;
+ _data->data = (unsigned char *) malloc (_data->size);
+ if (!_data->data) {
+ error = GPG_ERR_ENOMEM;
+ goto cleanup;
+ }
+ need_free__data = 1;
+ memmove (_data->data, src_data, _data->size);
+ }
+
+ switch (reverse) {
+ case REVERSE_BYTES:
+ reverse_buffer (_data->data, _data->size);
+ break;
+ default:
+ error = GPG_ERR_INV_DATA;
+ goto cleanup;
+ }
+ }
if (
(error = common_map_pkcs11_error (
@@ -1227,12 +1383,12 @@ gpg_error_t cmd_pksign (assuan_context_t ctx, char *line)
goto cleanup;
}
session_locked = 1;
-
+
if (
(error = common_map_pkcs11_error (
pkcs11h_certificate_signAny (
cert,
- CKM_RSA_PKCS,
+ mech,
_data->data,
_data->size,
NULL,
@@ -1252,7 +1408,7 @@ gpg_error_t cmd_pksign (assuan_context_t ctx, char *line)
(error = common_map_pkcs11_error (
pkcs11h_certificate_signAny (
cert,
- CKM_RSA_PKCS,
+ mech,
_data->data,
_data->size,
sig,
@@ -1291,8 +1447,7 @@ cleanup:
if (need_free__data) {
free (_data->data);
_data->data = NULL;
- free (_data);
- _data = NULL;
+ _data->size = 0;
}
return gpg_error (error);
@@ -1318,24 +1473,8 @@ gpg_error_t cmd_pkdecrypt (assuan_context_t ctx, char *line)
goto cleanup;
}
- /*
- * Guess.. taken from openpgp card implementation
- * and java PKCS#11 provider.
- */
_data.data = data->data;
_data.size = data->size;
- if (
- *_data.data == 0 && (
- _data.size == 129 ||
- _data.size == 193 ||
- _data.size == 257 ||
- _data.size == 385 ||
- _data.size == 513
- )
- ) {
- _data.data++;
- _data.size--;
- }
if (
(error = _get_certificate_by_name (
@@ -1349,6 +1488,61 @@ gpg_error_t cmd_pkdecrypt (assuan_context_t ctx, char *line)
goto cleanup;
}
+ CK_MECHANISM_TYPE mech;
+ unsigned int key_len = 0;
+ switch (get_key_subtype (ctx, cert_id)) {
+ case KEY_RSA_RSA:
+ mech = CKM_RSA_PKCS;
+ break;
+ case KEY_ECC_GOST2001:
+ mech = CKM_GOSTR3410_DERIVE;
+ key_len = 64;
+ break;
+ case KEY_ECC_GOST2012_256:
+ mech = CKM_GOSTR3410_12_DERIVE;
+ key_len = 64;
+ break;
+ case KEY_ECC_GOST2012_512:
+ mech = CKM_GOSTR3410_12_DERIVE;
+ key_len = 128;
+ break;
+ default:
+ error = GPG_ERR_UNSUPPORTED_ALGORITHM;
+ goto cleanup;
+ }
+
+ switch (mech) {
+ case CKM_GOSTR3410_DERIVE:
+ case CKM_GOSTR3410_12_DERIVE:
+ if (_data.size % 2 && _data.data[0] == 0x04) {
+ // Uncompressed point
+ _data.data++;
+ _data.size--;
+ }
+ /* Reverse byte order of each value: X Y UKM */
+ reverse_buffer (_data.data, key_len/2);
+ reverse_buffer (_data.data + key_len/2, key_len/2);
+ reverse_buffer (_data.data + key_len, _data.size - key_len);
+ break;
+ default:
+ /*
+ * Guess.. taken from openpgp card implementation
+ * and java PKCS#11 provider.
+ */
+ if (
+ *_data.data == 0 && (
+ _data.size == 129 ||
+ _data.size == 193 ||
+ _data.size == 257 ||
+ _data.size == 385 ||
+ _data.size == 513
+ )
+ ) {
+ _data.data++;
+ _data.size--;
+ }
+ }
+
if (
(error = common_map_pkcs11_error (
pkcs11h_certificate_create (
@@ -1372,19 +1566,26 @@ gpg_error_t cmd_pkdecrypt (assuan_context_t ctx, char *line)
}
session_locked = 1;
- if (
- (error = common_map_pkcs11_error (
- pkcs11h_certificate_decryptAny (
- cert,
- CKM_RSA_PKCS,
- _data.data,
- _data.size,
- NULL,
- &ptext_len
- )
- )) != GPG_ERR_NO_ERROR
- ) {
- goto cleanup;
+ switch ( mech ) {
+ case CKM_GOSTR3410_DERIVE:
+ case CKM_GOSTR3410_12_DERIVE:
+ ptext_len = key_len;
+ break;
+ default:
+ if (
+ (error = common_map_pkcs11_error (
+ pkcs11h_certificate_decryptAny (
+ cert,
+ mech,
+ _data.data,
+ _data.size,
+ NULL,
+ &ptext_len
+ )
+ )) != GPG_ERR_NO_ERROR
+ ) {
+ goto cleanup;
+ }
}
if ((ptext = (unsigned char *)malloc (ptext_len)) == NULL) {
@@ -1396,7 +1597,7 @@ gpg_error_t cmd_pkdecrypt (assuan_context_t ctx, char *line)
(error = common_map_pkcs11_error (
pkcs11h_certificate_decryptAny (
cert,
- CKM_RSA_PKCS,
+ mech,
_data.data,
_data.size,
ptext,
@@ -1674,12 +1875,10 @@ gpg_error_t cmd_genkey (assuan_context_t ctx, char *line)
{
gpg_err_code_t error = GPG_ERR_GENERAL;
pkcs11h_certificate_id_t cert_id = NULL;
- gcry_mpi_t n_mpi = NULL;
- gcry_mpi_t e_mpi = NULL;
- unsigned char *n_hex = NULL;
- unsigned char *e_hex = NULL;
- char *n_resp = strdup ("n ");
- char *e_resp = strdup ("e ");
+ cert_params_t *params = NULL;
+ unsigned char *hex[] = {NULL, NULL, NULL};
+ char *resp[] = {NULL, NULL, NULL};
+ int i, count = 0;
unsigned char *blob = NULL;
char *serial = NULL;
char *key = NULL;
@@ -1758,94 +1957,82 @@ gpg_error_t cmd_genkey (assuan_context_t ctx, char *line)
&blob,
&blob_size
)) != GPG_ERR_NO_ERROR ||
- (error = keyutil_get_cert_mpi (
+ (error = keyutil_get_cert_params (
blob,
blob_size,
- &n_mpi,
- &e_mpi
+ ¶ms
)) != GPG_ERR_NO_ERROR
) {
goto cleanup;
}
- if (
- gcry_mpi_aprint (
- GCRYMPI_FMT_HEX,
- &n_hex,
- NULL,
- n_mpi
- ) ||
- gcry_mpi_aprint (
- GCRYMPI_FMT_HEX,
- &e_hex,
- NULL,
- e_mpi
- )
- ) {
+ switch (params->key_type) {
+ case KEY_RSA:
+ resp[0] = strdup ("n ");
+ resp[1] = strdup ("e ");
+ count = 2;
+ break;
+ case KEY_ECC:
+ resp[0] = strdup ("X ");
+ resp[1] = strdup ("Y ");
+ resp[2] = strdup ("Z ");
+ count = 3;
+ break;
+ default:
error = GPG_ERR_BAD_KEY;
goto cleanup;
}
- if (
- !encoding_strappend (&n_resp, (char *)n_hex) ||
- !encoding_strappend (&e_resp, (char *)e_hex)
- ) {
- error = GPG_ERR_ENOMEM;
- goto cleanup;
- }
-
- if (
- (error = assuan_write_status(
- ctx,
- "KEY-DATA",
- n_resp
- )) != GPG_ERR_NO_ERROR
- ) {
- goto cleanup;
- }
-
- if (
- (error = assuan_write_status(
- ctx,
- "KEY-DATA",
- e_resp
- )) != GPG_ERR_NO_ERROR
- ) {
- goto cleanup;
+ gcry_mpi_t mpis[] = {params->a, params->b, params->c};
+ for (i = 0; i < count; ++i) {
+ if (resp[i] == NULL) {
+ error = GPG_ERR_ENOMEM;
+ goto cleanup;
+ }
+ if (
+ gcry_mpi_aprint (
+ GCRYMPI_FMT_HEX,
+ &hex[i],
+ NULL,
+ mpis[i]
+ )
+ ) {
+ error = GPG_ERR_BAD_KEY;
+ goto cleanup;
+ }
+ if (!encoding_strappend (&resp[i], (char *) hex[i])) {
+ error = GPG_ERR_ENOMEM;
+ goto cleanup;
+ }
+ if (
+ (error = assuan_write_status(
+ ctx,
+ "KEY-DATA",
+ resp[i]
+ )) != GPG_ERR_NO_ERROR
+ ) {
+ goto cleanup;
+ }
}
error = GPG_ERR_NO_ERROR;
cleanup:
- if (n_mpi != NULL) {
- gcry_mpi_release (n_mpi);
- n_mpi = NULL;
- }
-
- if (e_mpi != NULL) {
- gcry_mpi_release (e_mpi);
- e_mpi = NULL;
- }
-
- if (n_hex != NULL) {
- gcry_free (n_hex);
- n_hex = NULL;
- }
+ keyutil_params_free (params);
- if (e_hex != NULL) {
- gcry_free (e_hex);
- e_hex = NULL;
- }
-
- if (n_resp != NULL) {
- free (n_resp);
- n_resp = NULL;
+ for (i = 0; i < sizeof(hex)/sizeof(hex[0]); ++i) {
+ if (hex[i] != NULL) {
+ gcry_free (hex[i]);
+ hex[i] = NULL;
+ }
}
- if (e_resp != NULL) {
- free (e_resp);
- e_resp = NULL;
+ for (i = 0; i < sizeof(resp)/sizeof(resp[0]); ++i) {
+ if (resp[i] != NULL) {
+ free (resp[i]);
+ resp[i] = NULL;
+ }
}
if (blob != NULL) {
@@ -1865,4 +2052,3 @@ cleanup:
return gpg_error (error);
}
-
diff --git a/gnupg-pkcs11-scd/common.c b/gnupg-pkcs11-scd/common.c
index 41f4c6a..918dbe2 100644
--- a/gnupg-pkcs11-scd/common.c
+++ b/gnupg-pkcs11-scd/common.c
@@ -118,3 +118,32 @@ common_map_pkcs11_error (int rv) {
return error;
}
+void
+reverse_buffer (unsigned char *buffer, unsigned int length)
+{
+ unsigned int tmp, i;
+
+ for (i = 0; i < length/2; i++) {
+ tmp = buffer[i];
+ buffer[i] = buffer[length - 1 -i];
+ buffer[length - 1 - i] = tmp;
+ }
+}
+
+void
+reverse_hex (unsigned char *hex)
+{
+ unsigned char tmp_l, tmp_h;
+ unsigned int i, length;
+
+ length = strlen (hex);
+
+ for (i = 0; i < length/2 && (i + 1) < length; i += 2) {
+ tmp_h = hex[i];
+ tmp_l = hex[i + 1];
+ hex[i] = hex[length - 2 - i];
+ hex[i+1] = hex[length - 1 - i];
+ hex[length - 2 - i] = tmp_h;
+ hex[length - 1 - i] = tmp_l;
+ }
+}
diff --git a/gnupg-pkcs11-scd/common.h b/gnupg-pkcs11-scd/common.h
index 6ab37db..2c30598 100644
--- a/gnupg-pkcs11-scd/common.h
+++ b/gnupg-pkcs11-scd/common.h
@@ -84,4 +84,9 @@ common_log (
...
);
+void
+reverse_buffer (unsigned char *buffer, unsigned int length);
+void
+reverse_hex (unsigned char *hex);
+
#endif
diff --git a/gnupg-pkcs11-scd/gnupg-pkcs11-scd.1 b/gnupg-pkcs11-scd/gnupg-pkcs11-scd.1
index bf68366..b37a4b7 100644
--- a/gnupg-pkcs11-scd/gnupg-pkcs11-scd.1
+++ b/gnupg-pkcs11-scd/gnupg-pkcs11-scd.1
@@ -266,7 +266,7 @@ Typical steps to set up a card for gpg-2.0 usage:
.It
Acquire key ids:
.Dl gpg-agent --server gpg-connect-agent
-Enter "SCD LEARN" and look for "KEY-FRIEDNLY" responses, the first field is the hash, the second
+Enter "SCD LEARN" and look for "KEY-FRIENDLY" responses, the first field is the hash, the second
is the subject name.
.It
Instruct GnuPG to discover all useful information of card:
@@ -303,7 +303,7 @@ Refresh local key store:
.It
Acquire key ids:
.Dl gpg-agent --server gpg-connect-agent
-Enter "SCD LEARN" and look for "KEY-FRIEDNLY" responses, the first field is the keygrip, the second
+Enter "SCD LEARN" and look for "KEY-FRIENDLY" responses, the first field is the keygrip, the second
is the subject name.
.It
Create master key based on existing key using:
diff --git a/gnupg-pkcs11-scd/keyutil.c b/gnupg-pkcs11-scd/keyutil.c
index 1c99d2a..59d9e9e 100644
--- a/gnupg-pkcs11-scd/keyutil.c
+++ b/gnupg-pkcs11-scd/keyutil.c
@@ -62,29 +62,30 @@ void RSA_get0_key(const RSA *r, const BIGNUM **n, const BIGNUM **e, const BIGNUM
#endif
gpg_err_code_t
-keyutil_get_cert_mpi (
+keyutil_get_cert_params (
unsigned char *der,
size_t len,
- gcry_mpi_t *p_n_mpi,
- gcry_mpi_t *p_e_mpi
+ cert_params_t **params
) {
gpg_err_code_t error = GPG_ERR_GENERAL;
- gcry_mpi_t n_mpi = NULL;
- gcry_mpi_t e_mpi = NULL;
#if defined(ENABLE_GNUTLS)
gnutls_x509_crt_t cert = NULL;
gnutls_datum_t datum = {der, len};
gnutls_datum_t m = {NULL, 0}, e = {NULL, 0};
+ *params = gnutls_malloc (sizeof (**params));
#elif defined(ENABLE_OPENSSL)
X509 *x509 = NULL;
EVP_PKEY *pubkey = NULL;
RSA *rsa = NULL;
- const BIGNUM *n, *e;
- char *n_hex = NULL, *e_hex = NULL;
+ EC_KEY* ec_key = NULL; int ec_key_ref = 0;
+ const BIGNUM *a = NULL, *b = NULL, *c = NULL;
+ char *a_hex = NULL, *b_hex = NULL, *c_hex = NULL;
+ *params = OPENSSL_malloc (sizeof (**params));
#endif
- *p_n_mpi = NULL;
- *p_e_mpi = NULL;
+ (*params)->a = NULL;
+ (*params)->b = NULL;
+ (*params)->c = NULL;
#if defined(ENABLE_GNUTLS)
if (gnutls_x509_crt_init (&cert) != GNUTLS_E_SUCCESS) {
@@ -106,8 +107,8 @@ keyutil_get_cert_mpi (
}
if (
- gcry_mpi_scan(&n_mpi, GCRYMPI_FMT_USG, m.data, m.size, NULL) ||
- gcry_mpi_scan(&e_mpi, GCRYMPI_FMT_USG, e.data, e.size, NULL)
+ gcry_mpi_scan(&(*params)->a, GCRYMPI_FMT_USG, m.data, m.size, NULL) ||
+ gcry_mpi_scan(&(*params)->b, GCRYMPI_FMT_USG, e.data, e.size, NULL)
) {
error = GPG_ERR_BAD_KEY;
goto cleanup;
@@ -122,51 +123,99 @@ keyutil_get_cert_mpi (
error = GPG_ERR_BAD_CERT;
goto cleanup;
}
-
- if ((rsa = EVP_PKEY_get1_RSA(pubkey)) == NULL) {
- error = GPG_ERR_WRONG_PUBKEY_ALGO;
- goto cleanup;
- }
-
- RSA_get0_key(rsa, &n, &e, NULL);
- n_hex = BN_bn2hex (n);
- e_hex = BN_bn2hex (e);
-
- if(n_hex == NULL || e_hex == NULL) {
- error = GPG_ERR_BAD_KEY;
- goto cleanup;
+ int pubkey_type = EVP_PKEY_id(pubkey);
+
+ switch (pubkey_type) {
+ case EVP_PKEY_RSA:
+ (*params)->key_type = KEY_RSA;
+ (*params)->key_subtype = KEY_RSA_RSA;
+ if ((rsa = EVP_PKEY_get1_RSA(pubkey)) == NULL) {
+ error = GPG_ERR_WRONG_PUBKEY_ALGO;
+ goto cleanup;
+ }
+ RSA_get0_key(rsa, &a, &b, NULL);
+ if ( a ) a_hex = BN_bn2hex (a);
+ if ( b ) b_hex = BN_bn2hex (b);
+ if (a_hex == NULL || b_hex == NULL) {
+ error = GPG_ERR_BAD_CERT;
+ goto cleanup;
+ }
+ break;
+ case NID_id_GostR3410_2001:
+ (*params)->key_subtype = KEY_ECC_GOST2001;
+ goto gostkey;
+ case NID_id_GostR3410_2012_256:
+ (*params)->key_subtype = KEY_ECC_GOST2012_256;
+ goto gostkey;
+ case NID_id_GostR3410_2012_512:
+ (*params)->key_subtype = KEY_ECC_GOST2012_512;
+ goto gostkey;
+ gostkey:
+ ec_key = (EC_KEY *) EVP_PKEY_get0(pubkey);
+ goto ecc;
+ ecc:
+ case EVP_PKEY_EC:
+ (*params)->key_type = KEY_ECC;
+ if (!ec_key) {
+ ec_key = EVP_PKEY_get1_EC_KEY(pubkey);
+ ec_key_ref = 1;
+ }
+ int ret = 0;
+ if (ec_key) {
+ const EC_GROUP *group = EC_KEY_get0_group(ec_key);
+ const EC_POINT *pub_key = EC_KEY_get0_public_key(ec_key);
+
+ if (group && pub_key) {
+ (*params)->nid = EC_GROUP_get_curve_name(group);
+ BIGNUM *X = BN_new(), *Y = BN_new(), *Z = BN_new();
+ if (X && Y && Z) {
+ ret = EC_POINT_get_Jprojective_coordinates_GFp(group,
+ pub_key,
+ X, Y, Z,
+ NULL);
+ if (ret) {
+ a_hex = BN_bn2hex (X);
+ b_hex = BN_bn2hex (Y);
+ c_hex = BN_bn2hex (Z);
+ }
+ BN_free(X); BN_free(Y); BN_free(Z);
+ }
+ }
+ if (ec_key_ref)
+ EC_KEY_free(ec_key);
+ }
+
+ if (!ret) {
+ error = GPG_ERR_BAD_CERT;
+ goto cleanup;
+ }
+ if (a_hex == NULL || b_hex == NULL || c_hex == NULL) {
+ error = GPG_ERR_BAD_CERT;
+ goto cleanup;
+ }
+ break;
+ /*default:
+ error = GPG_ERR_WRONG_PUBKEY_ALGO;
+ goto cleanup;*/
}
if (
- gcry_mpi_scan (&n_mpi, GCRYMPI_FMT_HEX, n_hex, 0, NULL) ||
- gcry_mpi_scan (&e_mpi, GCRYMPI_FMT_HEX, e_hex, 0, NULL)
+ a_hex && gcry_mpi_scan (&(*params)->a, GCRYMPI_FMT_HEX, a_hex, 0, NULL) ||
+ b_hex && gcry_mpi_scan (&(*params)->b, GCRYMPI_FMT_HEX, b_hex, 0, NULL) ||
+ c_hex && gcry_mpi_scan (&(*params)->c, GCRYMPI_FMT_HEX, c_hex, 0, NULL)
) {
- error = GPG_ERR_BAD_KEY;
+ error = GPG_ERR_BAD_KEY;
goto cleanup;
}
#else
#error Invalid configuration.
#endif
- *p_n_mpi = n_mpi;
- n_mpi = NULL;
- *p_e_mpi = e_mpi;
- e_mpi = NULL;
error = GPG_ERR_NO_ERROR;
cleanup:
- if (n_mpi != NULL) {
- gcry_mpi_release (n_mpi);
- n_mpi = NULL;
- }
-
- if (e_mpi != NULL) {
- gcry_mpi_release (e_mpi);
- e_mpi = NULL;
- }
-
#if defined(ENABLE_GNUTLS)
if (m.data != NULL) {
@@ -200,23 +249,55 @@ cleanup:
RSA_free(rsa);
rsa = NULL;
}
-
- if (n_hex != NULL) {
- OPENSSL_free (n_hex);
- n_hex = NULL;
+
+ if (a_hex != NULL) {
+ OPENSSL_free (a_hex);
+ a_hex = NULL;
}
-
- if (e_hex != NULL) {
- OPENSSL_free (e_hex);
- e_hex = NULL;
+ if (b_hex != NULL) {
+ OPENSSL_free (b_hex);
+ b_hex = NULL;
+ }
+ if (c_hex != NULL) {
+ OPENSSL_free (c_hex);
+ c_hex = NULL;
}
#else
#error Invalid configuration.
#endif
+ if (error != GPG_ERR_NO_ERROR) {
+ keyutil_params_free (*params);
+ *params = NULL;
+ }
+
return error;
}
+
+void
+keyutil_params_free (cert_params_t *params) {
+ if (params) {
+ if (params->a) {
+ gcry_mpi_release (params->a);
+ params->a = NULL;
+ }
+ if (params->b) {
+ gcry_mpi_release (params->b);
+ params->b = NULL;
+ }
+ if (params->c) {
+ gcry_mpi_release (params->c);
+ params->c = NULL;
+ }
+#if defined(ENABLE_GNUTLS)
+ gnutls_free (params);
+#elif defined(ENABLE_OPENSSL)
+ OPENSSL_free (params);
+#endif
+ }
+}
+
/**
Convert X.509 RSA public key into gcrypt internal sexp form. Only RSA
public keys are accepted at the moment. The resul is stored in *sexp,
@@ -230,50 +311,164 @@ keyutil_get_cert_sexp (
gcry_sexp_t *p_sexp
) {
gpg_err_code_t error = GPG_ERR_GENERAL;
- gcry_mpi_t n_mpi = NULL;
- gcry_mpi_t e_mpi = NULL;
+ cert_params_t *params = NULL;
+ const char *curve_name = NULL;
+ gcry_ctx_t r_ctx = NULL;
+ gcry_sexp_t keyparam = NULL;
gcry_sexp_t sexp = NULL;
if (
- (error = keyutil_get_cert_mpi (
- der,
- len,
- &n_mpi,
- &e_mpi
- )) != GPG_ERR_NO_ERROR
+ (error = keyutil_get_cert_params (der, len, ¶ms))
+ != GPG_ERR_NO_ERROR
) {
goto cleanup;
}
- if (
- gcry_sexp_build (
- &sexp,
- NULL,
- "(public-key (rsa (n %m) (e %m)))",
- n_mpi,
- e_mpi
- )
- ) {
- error = GPG_ERR_BAD_KEY;
+ switch (params->key_type) {
+ case KEY_RSA:
+ if (
+ gcry_sexp_build (
+ &sexp,
+ NULL,
+ "(public-key (rsa (n %m) (e %m)))",
+ params->a,
+ params->b
+ )
+ ) {
+ error = GPG_ERR_BAD_KEY;
+ goto cleanup;
+ }
+ break;
+ case KEY_ECC:
+ switch (params->nid) {
+ case NID_id_GostR3410_2001_CryptoPro_A_ParamSet:
+ switch (params->key_subtype) {
+ case KEY_ECC_GOST2001:
+ curve_name = "GOST2001-CryptoPro-A";
+ break;
+ case KEY_ECC_GOST2012_256:
+ curve_name = "GOST2012-256-B";
+ break;
+ default:
+ error = GPG_ERR_BAD_CERT;
+ goto cleanup;
+ }
+ break;
+ case NID_id_GostR3410_2001_CryptoPro_B_ParamSet:
+ switch (params->key_subtype) {
+ case KEY_ECC_GOST2001:
+ curve_name = "GOST2001-CryptoPro-B";
+ break;
+ case KEY_ECC_GOST2012_256:
+ curve_name = "GOST2012-256-C";
+ break;
+ default:
+ error = GPG_ERR_BAD_CERT;
+ goto cleanup;
+ }
+ break;
+ case NID_id_GostR3410_2001_CryptoPro_C_ParamSet:
+ switch (params->key_subtype) {
+ case KEY_ECC_GOST2001:
+ curve_name = "GOST2001-CryptoPro-C";
+ break;
+ case KEY_ECC_GOST2012_256:
+ curve_name = "GOST2012-256-D";
+ break;
+ default:
+ error = GPG_ERR_BAD_CERT;
+ goto cleanup;
+ }
+ break;
+ case NID_id_GostR3410_2001_CryptoPro_XchA_ParamSet:
+ curve_name = "GOST2001-CryptoPro-XchA";
+ break;
+ case NID_id_GostR3410_2001_CryptoPro_XchB_ParamSet:
+ curve_name = "GOST2001-CryptoPro-XchB";
+ break;
+ case NID_id_tc26_gost_3410_2012_256_paramSetA:
+ curve_name = "GOST2012-256-A";
+ case NID_id_tc26_gost_3410_2012_256_paramSetB:
+ curve_name = "GOST2012-256-B";
+ case NID_id_tc26_gost_3410_2012_256_paramSetC:
+ curve_name = "GOST2012-256-C";
+ case NID_id_tc26_gost_3410_2012_256_paramSetD:
+ curve_name = "GOST2012-256-D";
+ case NID_id_tc26_gost_3410_2012_512_paramSetA:
+ curve_name = "GOST2012-512-A";
+ break;
+ case NID_id_tc26_gost_3410_2012_512_paramSetB:
+ curve_name = "GOST2012-512-B";
+ break;
+ default:
+ error = GPG_ERR_BAD_CERT;
+ goto cleanup;
+ }
+
+ if (
+ gcry_sexp_build (
+ &keyparam,
+ NULL,
+ "(public-key\n"
+ " (ecc\n"
+ " (curve %s)\n"
+ " (q.x %m)\n"
+ " (q.y %m)\n"
+ " (q.z %m)))\n",
+ curve_name,
+ params->a,
+ params->b,
+ params->c
+ )
+ ) {
+ error = GPG_ERR_BAD_KEY;
+ goto cleanup;
+ }
+
+ error = gcry_mpi_ec_new (&r_ctx,
+ keyparam,
+ curve_name);
+ if (error != GPG_ERR_NO_ERROR) {
+ goto cleanup;
+ }
+
+ if (
+ gcry_sexp_build (
+ &sexp,
+ NULL,
+ "(public-key\n"
+ " (ecc\n"
+ " (curve %s)\n"
+ " (q %m)))\n",
+ curve_name,
+ gcry_mpi_ec_get_mpi ("q", r_ctx, 1)
+ )
+ ) {
+ error = GPG_ERR_BAD_KEY;
+ goto cleanup;
+ }
+ break;
+ default:
+ error = GPG_ERR_BAD_CERT;
goto cleanup;
}
-
+
*p_sexp = sexp;
sexp = NULL;
error = GPG_ERR_NO_ERROR;
cleanup:
- if (n_mpi != NULL) {
- gcry_mpi_release (n_mpi);
- n_mpi = NULL;
- }
+ keyutil_params_free (params);
- if (e_mpi != NULL) {
- gcry_mpi_release (e_mpi);
- e_mpi = NULL;
+ if (keyparam != NULL) {
+ gcry_sexp_release (keyparam);
+ keyparam = NULL;
+ }
+ if (r_ctx != NULL) {
+ gcry_ctx_release (r_ctx);
+ r_ctx = NULL;
}
-
if (sexp != NULL) {
gcry_sexp_release (sexp);
sexp = NULL;
diff --git a/gnupg-pkcs11-scd/keyutil.h b/gnupg-pkcs11-scd/keyutil.h
index c426410..7850904 100644
--- a/gnupg-pkcs11-scd/keyutil.h
+++ b/gnupg-pkcs11-scd/keyutil.h
@@ -31,14 +31,34 @@
#ifndef __KEYUTIL_H
#define __KEYUTIL_H
+typedef enum {KEY_RSA, KEY_ECC} key_type_t;
+typedef enum {
+ KEY_UNKNOWN,
+ KEY_RSA_RSA,
+ KEY_ECC_GOST2001,
+ KEY_ECC_GOST2012_256,
+ KEY_ECC_GOST2012_512
+} key_subtype_t;
+
+typedef struct {
+ key_type_t key_type;
+ key_subtype_t key_subtype;
+ int nid;
+ gcry_mpi_t a;
+ gcry_mpi_t b;
+ gcry_mpi_t c;
+} cert_params_t;
+
gpg_err_code_t
-keyutil_get_cert_mpi (
+keyutil_get_cert_params (
unsigned char *der,
size_t len,
- gcry_mpi_t *p_n_mpi,
- gcry_mpi_t *p_e_mpi
+ cert_params_t **params
);
+void
+keyutil_params_free (cert_params_t *params);
+
gpg_err_code_t
keyutil_get_cert_sexp (
unsigned char *der,
@@ -46,6 +66,7 @@ keyutil_get_cert_sexp (
gcry_sexp_t *p_sexp
);
-char *keyutil_get_cert_hexgrip (gcry_sexp_t sexp);
+char *
+keyutil_get_cert_hexgrip (gcry_sexp_t sexp);
#endif
diff --git a/gnupg-pkcs11-scd/scdaemon.c b/gnupg-pkcs11-scd/scdaemon.c
index d646584..a7fb5c1 100644
--- a/gnupg-pkcs11-scd/scdaemon.c
+++ b/gnupg-pkcs11-scd/scdaemon.c
@@ -56,6 +56,10 @@
#endif
#endif
+#if defined(ENABLE_OPENSSL)
+#include <openssl/conf.h>
+#endif
+
#if defined(USE_GNUTLS)
#include <gnutls/gnutls.h>
#endif
@@ -787,6 +791,36 @@ static char *get_home_dir (void) {
return home_dir;
}
+static void
+my_gcry_logger (void * _global, int level, const char *fmt, va_list arg_ptr)
+{
+ global_t *global = (global_t *) _global;
+
+ /* Map the log levels. */
+ switch ( level ) {
+ case GCRY_LOG_CONT:
+ case GCRY_LOG_INFO:
+ if ( !global->config.verbose ) return;
+ break;
+ case GCRY_LOG_WARN:
+ case GCRY_LOG_ERROR:
+ case GCRY_LOG_FATAL:
+ case GCRY_LOG_BUG:
+ break;
+ case GCRY_LOG_DEBUG:
+ if ( !global->config.debug ) return;
+ break;
+ }
+
+ FILE *log_stream = common_get_log_stream ();
+ if ( log_stream ) {
+ vfprintf (log_stream, fmt, arg_ptr);
+ fflush (log_stream);
+ }
+
+ if ( level == GCRY_LOG_FATAL ) exit (1);
+}
+
int main (int argc, char *argv[])
{
enum {
@@ -1007,8 +1041,14 @@ int main (int argc, char *argv[])
);
}
+#if defined(ENABLE_OPENSSL)
+ OPENSSL_init_crypto(OPENSSL_INIT_LOAD_CONFIG, NULL);
+#endif
+
+ gcry_set_log_handler (my_gcry_logger, &global);
+
if (!gcry_check_version (GCRYPT_VERSION)) {
- common_log (LOG_FATAL, "Cannot initialize libcrypt");
+ common_log (LOG_FATAL, "Cannot initialize libgcrypt");
}
gcry_control (GCRYCTL_DISABLE_SECMEM, 0);
gcry_control (GCRYCTL_INITIALIZATION_FINISHED, 0);