mirror of
git://git.gnupg.org/gnupg.git
synced 2025-04-17 15:44:34 +02:00
* protect-tool.c (rsa_key_check): New.
(import_p12_file): New. (main): New command --p12-import. * minip12.c, minip12.h: New.
This commit is contained in:
parent
5c5a3f689a
commit
c65009a2c5
@ -1,8 +1,20 @@
|
|||||||
|
2002-06-25 Werner Koch <wk@gnupg.org>
|
||||||
|
|
||||||
|
* protect-tool.c (rsa_key_check): New.
|
||||||
|
(import_p12_file): New.
|
||||||
|
(main): New command --p12-import.
|
||||||
|
* minip12.c, minip12.h: New.
|
||||||
|
|
||||||
|
2002-06-24 Werner Koch <wk@gnupg.org>
|
||||||
|
|
||||||
|
* protect-tool.c (read_file): New.
|
||||||
|
(read_key): Factored most code out to read_file.
|
||||||
|
|
||||||
2002-06-17 Werner Koch <wk@gnupg.org>
|
2002-06-17 Werner Koch <wk@gnupg.org>
|
||||||
|
|
||||||
* agent.h: Add a callback function to the pin_entry_info structure.
|
* agent.h: Add a callback function to the pin_entry_info structure.
|
||||||
* query.c (agent_askpin): Use the callback to check for a correct
|
* query.c (agent_askpin): Use the callback to check for a correct
|
||||||
PIN. Removed the start_err_text argument becuase it is not
|
PIN. Removed the start_err_text argument because it is not
|
||||||
anymore needed; changed callers.
|
anymore needed; changed callers.
|
||||||
* findkey.c (unprotect): Replace our own check loop by a callback.
|
* findkey.c (unprotect): Replace our own check loop by a callback.
|
||||||
(try_unprotect_cb): New.
|
(try_unprotect_cb): New.
|
||||||
|
@ -47,8 +47,13 @@ gpg_agent_LDADD = ../jnlib/libjnlib.a ../assuan/libassuan.a \
|
|||||||
|
|
||||||
protect_tool_SOURCES = \
|
protect_tool_SOURCES = \
|
||||||
protect-tool.c \
|
protect-tool.c \
|
||||||
protect.c
|
protect.c \
|
||||||
|
minip12.c minip12.h
|
||||||
|
|
||||||
|
|
||||||
protect_tool_LDADD = ../jnlib/libjnlib.a \
|
protect_tool_LDADD = ../jnlib/libjnlib.a \
|
||||||
../common/libcommon.a $(LIBGCRYPT_LIBS)
|
../common/libcommon.a $(LIBGCRYPT_LIBS)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -75,7 +75,7 @@ The only available protection mode for now is
|
|||||||
|
|
||||||
openpgp-s2k3-sha1-aes-cbc
|
openpgp-s2k3-sha1-aes-cbc
|
||||||
|
|
||||||
which describesan algorithm using using AES in CBC mode for
|
which describes an algorithm using using AES in CBC mode for
|
||||||
encryption, SHA-1 for integrity protection and the String to Key
|
encryption, SHA-1 for integrity protection and the String to Key
|
||||||
algorithm 3 from OpenPGP (rfc2440).
|
algorithm 3 from OpenPGP (rfc2440).
|
||||||
|
|
||||||
@ -159,5 +159,5 @@ independent of any protocol, so that the same key can be ised with
|
|||||||
different protocols. PKCS-15 calls this a subjectKeyHash; it can be
|
different protocols. PKCS-15 calls this a subjectKeyHash; it can be
|
||||||
calculate using Libgcrypt's gcry_pk_get_keygrip().
|
calculate using Libgcrypt's gcry_pk_get_keygrip().
|
||||||
|
|
||||||
[3] Even when canonical representation is required we will show the
|
[3] Even when canonical representation are required we will show the
|
||||||
S-expression here in a more readable representation.
|
S-expression here in a more readable representation.
|
||||||
|
805
agent/minip12.c
Normal file
805
agent/minip12.c
Normal file
@ -0,0 +1,805 @@
|
|||||||
|
/* minip12.c - A minilam pkcs-12 implementation.
|
||||||
|
* Copyright (C) 2002 Free Software Foundation, Inc.
|
||||||
|
*
|
||||||
|
* This file is part of GnuPG.
|
||||||
|
*
|
||||||
|
* GnuPG is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* GnuPG is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifdef HAVE_CONFIG_H
|
||||||
|
#include <config.h>
|
||||||
|
#endif
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <assert.h>
|
||||||
|
#include <gcrypt.h>
|
||||||
|
|
||||||
|
#undef TEST
|
||||||
|
|
||||||
|
#ifdef TEST
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "../jnlib/logging.h"
|
||||||
|
#include "minip12.h"
|
||||||
|
|
||||||
|
#ifndef DIM
|
||||||
|
#define DIM(v) (sizeof(v)/sizeof((v)[0]))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
UNIVERSAL = 0,
|
||||||
|
APPLICATION = 1,
|
||||||
|
CONTEXT = 2,
|
||||||
|
PRIVATE = 3
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
TAG_NONE = 0,
|
||||||
|
TAG_BOOLEAN = 1,
|
||||||
|
TAG_INTEGER = 2,
|
||||||
|
TAG_BIT_STRING = 3,
|
||||||
|
TAG_OCTET_STRING = 4,
|
||||||
|
TAG_NULL = 5,
|
||||||
|
TAG_OBJECT_ID = 6,
|
||||||
|
TAG_OBJECT_DESCRIPTOR = 7,
|
||||||
|
TAG_EXTERNAL = 8,
|
||||||
|
TAG_REAL = 9,
|
||||||
|
TAG_ENUMERATED = 10,
|
||||||
|
TAG_EMBEDDED_PDV = 11,
|
||||||
|
TAG_UTF8_STRING = 12,
|
||||||
|
TAG_REALTIVE_OID = 13,
|
||||||
|
TAG_SEQUENCE = 16,
|
||||||
|
TAG_SET = 17,
|
||||||
|
TAG_NUMERIC_STRING = 18,
|
||||||
|
TAG_PRINTABLE_STRING = 19,
|
||||||
|
TAG_TELETEX_STRING = 20,
|
||||||
|
TAG_VIDEOTEX_STRING = 21,
|
||||||
|
TAG_IA5_STRING = 22,
|
||||||
|
TAG_UTC_TIME = 23,
|
||||||
|
TAG_GENERALIZED_TIME = 24,
|
||||||
|
TAG_GRAPHIC_STRING = 25,
|
||||||
|
TAG_VISIBLE_STRING = 26,
|
||||||
|
TAG_GENERAL_STRING = 27,
|
||||||
|
TAG_UNIVERSAL_STRING = 28,
|
||||||
|
TAG_CHARACTER_STRING = 29,
|
||||||
|
TAG_BMP_STRING = 30
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
static unsigned char const oid_data[9] = {
|
||||||
|
0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x07, 0x01 };
|
||||||
|
static unsigned char const oid_encryptedData[9] = {
|
||||||
|
0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x07, 0x06 };
|
||||||
|
static unsigned char const oid_pkcs_12_pkcs_8ShroudedKeyBag[11] = {
|
||||||
|
0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x0C, 0x0A, 0x01, 0x02 };
|
||||||
|
static unsigned char const oid_pbeWithSHAAnd3_KeyTripleDES_CBC[10] = {
|
||||||
|
0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x0C, 0x01, 0x03 };
|
||||||
|
|
||||||
|
static unsigned char const oid_rsaEncryption[9] = {
|
||||||
|
0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x01 };
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
struct tag_info {
|
||||||
|
int class;
|
||||||
|
int is_constructed;
|
||||||
|
unsigned long tag;
|
||||||
|
unsigned long length; /* length part of the TLV */
|
||||||
|
int nhdr;
|
||||||
|
int ndef; /* It is an indefinite length */
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/* Parse the buffer at the address BUFFER which is of SIZE and return
|
||||||
|
the tag and the length part from the TLV triplet. Update BUFFER
|
||||||
|
and SIZE on success. */
|
||||||
|
static int
|
||||||
|
parse_tag (unsigned char const **buffer, size_t *size, struct tag_info *ti)
|
||||||
|
{
|
||||||
|
int c;
|
||||||
|
unsigned long tag;
|
||||||
|
const unsigned char *buf = *buffer;
|
||||||
|
size_t length = *size;
|
||||||
|
|
||||||
|
ti->length = 0;
|
||||||
|
ti->ndef = 0;
|
||||||
|
ti->nhdr = 0;
|
||||||
|
|
||||||
|
/* Get the tag */
|
||||||
|
if (!length)
|
||||||
|
return -1; /* premature eof */
|
||||||
|
c = *buf++; length--;
|
||||||
|
ti->nhdr++;
|
||||||
|
|
||||||
|
ti->class = (c & 0xc0) >> 6;
|
||||||
|
ti->is_constructed = !!(c & 0x20);
|
||||||
|
tag = c & 0x1f;
|
||||||
|
|
||||||
|
if (tag == 0x1f)
|
||||||
|
{
|
||||||
|
tag = 0;
|
||||||
|
do
|
||||||
|
{
|
||||||
|
tag <<= 7;
|
||||||
|
if (!length)
|
||||||
|
return -1; /* premature eof */
|
||||||
|
c = *buf++; length--;
|
||||||
|
ti->nhdr++;
|
||||||
|
tag |= c & 0x7f;
|
||||||
|
}
|
||||||
|
while (c & 0x80);
|
||||||
|
}
|
||||||
|
ti->tag = tag;
|
||||||
|
|
||||||
|
/* Get the length */
|
||||||
|
if (!length)
|
||||||
|
return -1; /* prematureeof */
|
||||||
|
c = *buf++; length--;
|
||||||
|
ti->nhdr++;
|
||||||
|
|
||||||
|
if ( !(c & 0x80) )
|
||||||
|
ti->length = c;
|
||||||
|
else if (c == 0x80)
|
||||||
|
ti->ndef = 1;
|
||||||
|
else if (c == 0xff)
|
||||||
|
return -1; /* forbidden length value */
|
||||||
|
else
|
||||||
|
{
|
||||||
|
unsigned long len = 0;
|
||||||
|
int count = c & 0x7f;
|
||||||
|
|
||||||
|
for (; count; count--)
|
||||||
|
{
|
||||||
|
len <<= 8;
|
||||||
|
if (!length)
|
||||||
|
return -1; /* premature_eof */
|
||||||
|
c = *buf++; length--;
|
||||||
|
ti->nhdr++;
|
||||||
|
len |= c & 0xff;
|
||||||
|
}
|
||||||
|
ti->length = len;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ti->class == UNIVERSAL && !ti->tag)
|
||||||
|
ti->length = 0;
|
||||||
|
|
||||||
|
if (ti->length > length)
|
||||||
|
return -1; /* data larger than buffer. */
|
||||||
|
|
||||||
|
*buffer = buf;
|
||||||
|
*size = length;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int
|
||||||
|
string_to_key (int id, char *salt, int iter, const char *pw,
|
||||||
|
int req_keylen, unsigned char *keybuf)
|
||||||
|
{
|
||||||
|
int rc, i, j;
|
||||||
|
GcryMDHd md;
|
||||||
|
GcryMPI num_b1 = NULL;
|
||||||
|
int pwlen;
|
||||||
|
unsigned char hash[20], buf_b[64], buf_i[128], *p;
|
||||||
|
size_t cur_keylen;
|
||||||
|
size_t n;
|
||||||
|
|
||||||
|
cur_keylen = 0;
|
||||||
|
pwlen = strlen (pw);
|
||||||
|
if (pwlen > 63/2)
|
||||||
|
{
|
||||||
|
log_error ("password too long\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Store salt and password in BUF_I */
|
||||||
|
p = buf_i;
|
||||||
|
for(i=0; i < 64; i++)
|
||||||
|
*p++ = salt [i%8];
|
||||||
|
for(i=j=0; i < 64; i += 2)
|
||||||
|
{
|
||||||
|
*p++ = 0;
|
||||||
|
*p++ = pw[j];
|
||||||
|
if (++j > pwlen) /* Note, that we include the trailing zero */
|
||||||
|
j = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (;;)
|
||||||
|
{
|
||||||
|
md = gcry_md_open (GCRY_MD_SHA1, 0);
|
||||||
|
if (!md)
|
||||||
|
{
|
||||||
|
log_error ( "gcry_md_open failed: %s\n", gcry_strerror (-1));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
for(i=0; i < 64; i++)
|
||||||
|
gcry_md_putc (md, id);
|
||||||
|
gcry_md_write (md, buf_i, 128);
|
||||||
|
memcpy (hash, gcry_md_read (md, 0), 20);
|
||||||
|
gcry_md_close (md);
|
||||||
|
for (i=1; i < iter; i++)
|
||||||
|
gcry_md_hash_buffer (GCRY_MD_SHA1, hash, hash, 20);
|
||||||
|
|
||||||
|
for (i=0; i < 20 && cur_keylen < req_keylen; i++)
|
||||||
|
keybuf[cur_keylen++] = hash[i];
|
||||||
|
if (cur_keylen == req_keylen)
|
||||||
|
{
|
||||||
|
gcry_mpi_release (num_b1);
|
||||||
|
return 0; /* ready */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* need more bytes. */
|
||||||
|
for(i=0; i < 64; i++)
|
||||||
|
buf_b[i] = hash[i % 20];
|
||||||
|
n = 64;
|
||||||
|
rc = gcry_mpi_scan (&num_b1, GCRYMPI_FMT_USG, buf_b, &n);
|
||||||
|
if (rc)
|
||||||
|
{
|
||||||
|
log_error ( "gcry_mpi_scan failed: %s\n", gcry_strerror (rc));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
gcry_mpi_add_ui (num_b1, num_b1, 1);
|
||||||
|
for (i=0; i < 128; i += 64)
|
||||||
|
{
|
||||||
|
GcryMPI num_ij;
|
||||||
|
|
||||||
|
n = 64;
|
||||||
|
rc = gcry_mpi_scan (&num_ij, GCRYMPI_FMT_USG, buf_i + i, &n);
|
||||||
|
if (rc)
|
||||||
|
{
|
||||||
|
log_error ( "gcry_mpi_scan failed: %s\n",
|
||||||
|
gcry_strerror (rc));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
gcry_mpi_add (num_ij, num_ij, num_b1);
|
||||||
|
gcry_mpi_clear_highbit (num_ij, 64*8);
|
||||||
|
n = 64;
|
||||||
|
rc = gcry_mpi_print (GCRYMPI_FMT_USG, buf_i + i, &n, num_ij);
|
||||||
|
if (rc)
|
||||||
|
{
|
||||||
|
log_error ( "gcry_mpi_print failed: %s\n",
|
||||||
|
gcry_strerror (rc));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
gcry_mpi_release (num_ij);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int
|
||||||
|
set_key_iv (GcryCipherHd chd, char *salt, int iter, const char *pw)
|
||||||
|
{
|
||||||
|
unsigned char keybuf[24];
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
if (string_to_key (1, salt, iter, pw, 24, keybuf))
|
||||||
|
return -1;
|
||||||
|
rc = gcry_cipher_setkey (chd, keybuf, 24);
|
||||||
|
if (rc)
|
||||||
|
{
|
||||||
|
log_error ( "gcry_cipher_setkey failed: %s\n", gcry_strerror (rc));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (string_to_key (2, salt, iter, pw, 8, keybuf))
|
||||||
|
return -1;
|
||||||
|
rc = gcry_cipher_setiv (chd, keybuf, 8);
|
||||||
|
if (rc)
|
||||||
|
{
|
||||||
|
log_error ("gcry_cipher_setiv failed: %s\n", gcry_strerror (rc));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void
|
||||||
|
decrypt_block (unsigned char *buffer, size_t length, char *salt, int iter,
|
||||||
|
const char *pw)
|
||||||
|
{
|
||||||
|
GcryCipherHd chd;
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
chd = gcry_cipher_open (GCRY_CIPHER_3DES, GCRY_CIPHER_MODE_CBC, 0);
|
||||||
|
if (!chd)
|
||||||
|
{
|
||||||
|
log_error ( "gcry_cipher_open failed: %s\n", gcry_strerror(-1));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (set_key_iv (chd, salt, iter, pw))
|
||||||
|
goto leave;
|
||||||
|
|
||||||
|
rc = gcry_cipher_decrypt (chd, buffer, length, NULL, 0);
|
||||||
|
if (rc)
|
||||||
|
{
|
||||||
|
log_error ( "gcry_cipher_decrypt failed: %s\n", gcry_strerror (rc));
|
||||||
|
goto leave;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* { */
|
||||||
|
/* FILE *fp = fopen("inner.der", "wb"); */
|
||||||
|
/* fwrite (buffer, 1, length, fp); */
|
||||||
|
/* fclose (fp); */
|
||||||
|
/* } */
|
||||||
|
|
||||||
|
leave:
|
||||||
|
gcry_cipher_close (chd);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
static int
|
||||||
|
parse_bag_encrypted_data (const unsigned char *buffer, size_t length,
|
||||||
|
int startoffset)
|
||||||
|
{
|
||||||
|
struct tag_info ti;
|
||||||
|
const unsigned char *p = buffer;
|
||||||
|
size_t n = length;
|
||||||
|
const char *where;
|
||||||
|
|
||||||
|
where = "start";
|
||||||
|
if (parse_tag (&p, &n, &ti))
|
||||||
|
goto bailout;
|
||||||
|
if (ti.class != CONTEXT || ti.tag)
|
||||||
|
goto bailout;
|
||||||
|
if (parse_tag (&p, &n, &ti))
|
||||||
|
goto bailout;
|
||||||
|
if (ti.tag != TAG_SEQUENCE)
|
||||||
|
goto bailout;
|
||||||
|
|
||||||
|
where = "bag.encryptedData.version";
|
||||||
|
if (parse_tag (&p, &n, &ti))
|
||||||
|
goto bailout;
|
||||||
|
if (ti.tag != TAG_INTEGER || ti.length != 1 || *p != 0)
|
||||||
|
goto bailout;
|
||||||
|
p++; n--;
|
||||||
|
if (parse_tag (&p, &n, &ti))
|
||||||
|
goto bailout;
|
||||||
|
if (ti.tag != TAG_SEQUENCE)
|
||||||
|
goto bailout;
|
||||||
|
|
||||||
|
where = "bag.encryptedData.data";
|
||||||
|
if (parse_tag (&p, &n, &ti))
|
||||||
|
goto bailout;
|
||||||
|
if (ti.tag != TAG_OBJECT_ID || ti.length != DIM(oid_data)
|
||||||
|
|| memcmp (p, oid_data, DIM(oid_data)))
|
||||||
|
goto bailout;
|
||||||
|
p += DIM(oid_data);
|
||||||
|
n -= DIM(oid_data);
|
||||||
|
|
||||||
|
/* fixme: continue parsing */
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
bailout:
|
||||||
|
log_error ("encrptedData error at \"%s\", offset %u\n",
|
||||||
|
where, (p - buffer)+startoffset);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static GcryMPI *
|
||||||
|
parse_bag_data (const unsigned char *buffer, size_t length, int startoffset,
|
||||||
|
const char *pw)
|
||||||
|
{
|
||||||
|
int rc;
|
||||||
|
struct tag_info ti;
|
||||||
|
const unsigned char *p = buffer;
|
||||||
|
size_t n = length;
|
||||||
|
const char *where;
|
||||||
|
char salt[8];
|
||||||
|
unsigned int iter;
|
||||||
|
int len;
|
||||||
|
unsigned char *plain = NULL;
|
||||||
|
GcryMPI *result = NULL;
|
||||||
|
int result_count, i;
|
||||||
|
|
||||||
|
where = "start";
|
||||||
|
if (parse_tag (&p, &n, &ti))
|
||||||
|
goto bailout;
|
||||||
|
if (ti.class != CONTEXT || ti.tag)
|
||||||
|
goto bailout;
|
||||||
|
if (parse_tag (&p, &n, &ti))
|
||||||
|
goto bailout;
|
||||||
|
if (ti.class || ti.tag != TAG_OCTET_STRING)
|
||||||
|
goto bailout;
|
||||||
|
|
||||||
|
where = "data.outerseqs";
|
||||||
|
if (parse_tag (&p, &n, &ti))
|
||||||
|
goto bailout;
|
||||||
|
if (ti.class || ti.tag != TAG_SEQUENCE)
|
||||||
|
goto bailout;
|
||||||
|
if (parse_tag (&p, &n, &ti))
|
||||||
|
goto bailout;
|
||||||
|
if (ti.class || ti.tag != TAG_SEQUENCE)
|
||||||
|
goto bailout;
|
||||||
|
|
||||||
|
where = "data.objectidentifier";
|
||||||
|
if (parse_tag (&p, &n, &ti))
|
||||||
|
goto bailout;
|
||||||
|
if (ti.class || ti.tag != TAG_OBJECT_ID
|
||||||
|
|| ti.length != DIM(oid_pkcs_12_pkcs_8ShroudedKeyBag)
|
||||||
|
|| memcmp (p, oid_pkcs_12_pkcs_8ShroudedKeyBag,
|
||||||
|
DIM(oid_pkcs_12_pkcs_8ShroudedKeyBag)))
|
||||||
|
goto bailout;
|
||||||
|
p += DIM(oid_pkcs_12_pkcs_8ShroudedKeyBag);
|
||||||
|
n -= DIM(oid_pkcs_12_pkcs_8ShroudedKeyBag);
|
||||||
|
|
||||||
|
where = "shrouded,outerseqs";
|
||||||
|
if (parse_tag (&p, &n, &ti))
|
||||||
|
goto bailout;
|
||||||
|
if (ti.class != CONTEXT || ti.tag)
|
||||||
|
goto bailout;
|
||||||
|
if (parse_tag (&p, &n, &ti))
|
||||||
|
goto bailout;
|
||||||
|
if (ti.class || ti.tag != TAG_SEQUENCE)
|
||||||
|
goto bailout;
|
||||||
|
if (parse_tag (&p, &n, &ti))
|
||||||
|
goto bailout;
|
||||||
|
if (ti.class || ti.tag != TAG_SEQUENCE)
|
||||||
|
goto bailout;
|
||||||
|
if (parse_tag (&p, &n, &ti))
|
||||||
|
goto bailout;
|
||||||
|
if (ti.class || ti.tag != TAG_OBJECT_ID
|
||||||
|
|| ti.length != DIM(oid_pbeWithSHAAnd3_KeyTripleDES_CBC)
|
||||||
|
|| memcmp (p, oid_pbeWithSHAAnd3_KeyTripleDES_CBC,
|
||||||
|
DIM(oid_pbeWithSHAAnd3_KeyTripleDES_CBC)))
|
||||||
|
goto bailout;
|
||||||
|
p += DIM(oid_pbeWithSHAAnd3_KeyTripleDES_CBC);
|
||||||
|
n -= DIM(oid_pbeWithSHAAnd3_KeyTripleDES_CBC);
|
||||||
|
|
||||||
|
where = "3des-params";
|
||||||
|
if (parse_tag (&p, &n, &ti))
|
||||||
|
goto bailout;
|
||||||
|
if (ti.class || ti.tag != TAG_SEQUENCE)
|
||||||
|
goto bailout;
|
||||||
|
if (parse_tag (&p, &n, &ti))
|
||||||
|
goto bailout;
|
||||||
|
if (ti.class || ti.tag != TAG_OCTET_STRING || ti.length != 8 )
|
||||||
|
goto bailout;
|
||||||
|
memcpy (salt, p, 8);
|
||||||
|
p += 8;
|
||||||
|
n -= 8;
|
||||||
|
if (parse_tag (&p, &n, &ti))
|
||||||
|
goto bailout;
|
||||||
|
if (ti.class || ti.tag != TAG_INTEGER || !ti.length )
|
||||||
|
goto bailout;
|
||||||
|
for (iter=0; ti.length; ti.length--)
|
||||||
|
{
|
||||||
|
iter <<= 8;
|
||||||
|
iter |= (*p++) & 0xff;
|
||||||
|
n--;
|
||||||
|
}
|
||||||
|
|
||||||
|
where = "3des-ciphertext";
|
||||||
|
if (parse_tag (&p, &n, &ti))
|
||||||
|
goto bailout;
|
||||||
|
if (ti.class || ti.tag != TAG_OCTET_STRING || !ti.length )
|
||||||
|
goto bailout;
|
||||||
|
|
||||||
|
log_info ("%lu bytes of 3DES encrypted text\n", ti.length);
|
||||||
|
|
||||||
|
plain = gcry_malloc_secure (ti.length);
|
||||||
|
if (!plain)
|
||||||
|
{
|
||||||
|
log_error ("error allocating decryption buffer\n");
|
||||||
|
goto bailout;
|
||||||
|
}
|
||||||
|
memcpy (plain, p, ti.length);
|
||||||
|
decrypt_block (plain, ti.length, salt, iter, pw);
|
||||||
|
n = ti.length;
|
||||||
|
startoffset = 0;
|
||||||
|
buffer = p = plain;
|
||||||
|
|
||||||
|
where = "decrypted-text";
|
||||||
|
if (parse_tag (&p, &n, &ti) || ti.class || ti.tag != TAG_SEQUENCE)
|
||||||
|
goto bailout;
|
||||||
|
if (parse_tag (&p, &n, &ti) || ti.class || ti.tag != TAG_INTEGER
|
||||||
|
|| ti.length != 1 || *p)
|
||||||
|
goto bailout;
|
||||||
|
p++; n--;
|
||||||
|
if (parse_tag (&p, &n, &ti) || ti.class || ti.tag != TAG_SEQUENCE)
|
||||||
|
goto bailout;
|
||||||
|
len = ti.length;
|
||||||
|
if (parse_tag (&p, &n, &ti))
|
||||||
|
goto bailout;
|
||||||
|
if (len < ti.nhdr)
|
||||||
|
goto bailout;
|
||||||
|
len -= ti.nhdr;
|
||||||
|
if (ti.class || ti.tag != TAG_OBJECT_ID
|
||||||
|
|| ti.length != DIM(oid_rsaEncryption)
|
||||||
|
|| memcmp (p, oid_rsaEncryption,
|
||||||
|
DIM(oid_rsaEncryption)))
|
||||||
|
goto bailout;
|
||||||
|
p += DIM (oid_rsaEncryption);
|
||||||
|
n -= DIM (oid_rsaEncryption);
|
||||||
|
if (len < ti.length)
|
||||||
|
goto bailout;
|
||||||
|
len -= ti.length;
|
||||||
|
if (n < len)
|
||||||
|
goto bailout;
|
||||||
|
p += len;
|
||||||
|
n -= len;
|
||||||
|
if (parse_tag (&p, &n, &ti) || ti.class || ti.tag != TAG_OCTET_STRING)
|
||||||
|
goto bailout;
|
||||||
|
if (parse_tag (&p, &n, &ti) || ti.class || ti.tag != TAG_SEQUENCE)
|
||||||
|
goto bailout;
|
||||||
|
len = ti.length;
|
||||||
|
|
||||||
|
result = gcry_calloc (10, sizeof *result);
|
||||||
|
if (!result)
|
||||||
|
{
|
||||||
|
log_error ( "error allocating result array\n");
|
||||||
|
goto bailout;
|
||||||
|
}
|
||||||
|
result_count = 0;
|
||||||
|
|
||||||
|
where = "reading.key-parameters";
|
||||||
|
for (result_count=0; len && result_count < 9;)
|
||||||
|
{
|
||||||
|
int dummy_n;
|
||||||
|
|
||||||
|
if (parse_tag (&p, &n, &ti) || ti.class || ti.tag != TAG_INTEGER)
|
||||||
|
goto bailout;
|
||||||
|
if (len < ti.nhdr)
|
||||||
|
goto bailout;
|
||||||
|
len -= ti.nhdr;
|
||||||
|
if (len < ti.length)
|
||||||
|
goto bailout;
|
||||||
|
len -= ti.length;
|
||||||
|
dummy_n = ti.length;
|
||||||
|
if (!result_count && ti.length == 1 && !*p)
|
||||||
|
; /* ignore the very first one if it is a 0 */
|
||||||
|
else
|
||||||
|
{
|
||||||
|
rc = gcry_mpi_scan (result+result_count, GCRYMPI_FMT_USG, p,
|
||||||
|
&dummy_n);
|
||||||
|
if (rc)
|
||||||
|
{
|
||||||
|
log_error ("error parsing key parameter: %s\n",
|
||||||
|
gcry_strerror (rc));
|
||||||
|
goto bailout;
|
||||||
|
}
|
||||||
|
result_count++;
|
||||||
|
}
|
||||||
|
p += ti.length;
|
||||||
|
n -= ti.length;
|
||||||
|
}
|
||||||
|
if (len)
|
||||||
|
goto bailout;
|
||||||
|
|
||||||
|
return result;
|
||||||
|
|
||||||
|
bailout:
|
||||||
|
gcry_free (plain);
|
||||||
|
if (result)
|
||||||
|
{
|
||||||
|
for (i=0; result[i]; i++)
|
||||||
|
gcry_mpi_release (result[i]);
|
||||||
|
gcry_free (result);
|
||||||
|
}
|
||||||
|
log_error ( "data error at \"%s\", offset %u\n",
|
||||||
|
where, (p - buffer) + startoffset);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Parse a PKCS12 object and return an array of MPI representing the
|
||||||
|
secret key parameters. This is a very limited inplementation in
|
||||||
|
that it is only able to look for 3DES encoded enctyptedData and
|
||||||
|
tries to extract the first private key object it finds. In case of
|
||||||
|
an error NULL is returned. */
|
||||||
|
GcryMPI *
|
||||||
|
p12_parse (const unsigned char *buffer, size_t length, const char *pw)
|
||||||
|
{
|
||||||
|
struct tag_info ti;
|
||||||
|
const unsigned char *p = buffer;
|
||||||
|
size_t n = length;
|
||||||
|
const char *where;
|
||||||
|
int bagseqlength, len;
|
||||||
|
|
||||||
|
where = "pfx";
|
||||||
|
if (parse_tag (&p, &n, &ti))
|
||||||
|
goto bailout;
|
||||||
|
if (ti.tag != TAG_SEQUENCE)
|
||||||
|
goto bailout;
|
||||||
|
|
||||||
|
where = "pfxVersion";
|
||||||
|
if (parse_tag (&p, &n, &ti))
|
||||||
|
goto bailout;
|
||||||
|
if (ti.tag != TAG_INTEGER || ti.length != 1 || *p != 3)
|
||||||
|
goto bailout;
|
||||||
|
p++; n--;
|
||||||
|
|
||||||
|
where = "authSave";
|
||||||
|
if (parse_tag (&p, &n, &ti))
|
||||||
|
goto bailout;
|
||||||
|
if (ti.tag != TAG_SEQUENCE)
|
||||||
|
goto bailout;
|
||||||
|
if (parse_tag (&p, &n, &ti))
|
||||||
|
goto bailout;
|
||||||
|
if (ti.tag != TAG_OBJECT_ID || ti.length != DIM(oid_data)
|
||||||
|
|| memcmp (p, oid_data, DIM(oid_data)))
|
||||||
|
goto bailout;
|
||||||
|
p += DIM(oid_data);
|
||||||
|
n -= DIM(oid_data);
|
||||||
|
|
||||||
|
if (parse_tag (&p, &n, &ti))
|
||||||
|
goto bailout;
|
||||||
|
if (ti.class != CONTEXT || ti.tag)
|
||||||
|
goto bailout;
|
||||||
|
if (parse_tag (&p, &n, &ti))
|
||||||
|
goto bailout;
|
||||||
|
if (ti.class != UNIVERSAL || ti.tag != TAG_OCTET_STRING)
|
||||||
|
goto bailout;
|
||||||
|
|
||||||
|
where = "bags";
|
||||||
|
if (parse_tag (&p, &n, &ti))
|
||||||
|
goto bailout;
|
||||||
|
if (ti.class != UNIVERSAL || ti.tag != TAG_SEQUENCE)
|
||||||
|
goto bailout;
|
||||||
|
bagseqlength = ti.length;
|
||||||
|
while (bagseqlength)
|
||||||
|
{
|
||||||
|
log_error ( "at offset %u\n", (p - buffer));
|
||||||
|
where = "bag-sequence";
|
||||||
|
if (parse_tag (&p, &n, &ti))
|
||||||
|
goto bailout;
|
||||||
|
if (ti.class != UNIVERSAL || ti.tag != TAG_SEQUENCE)
|
||||||
|
goto bailout;
|
||||||
|
|
||||||
|
if (bagseqlength < ti.nhdr)
|
||||||
|
goto bailout;
|
||||||
|
bagseqlength -= ti.nhdr;
|
||||||
|
if (bagseqlength < ti.length)
|
||||||
|
goto bailout;
|
||||||
|
bagseqlength -= ti.length;
|
||||||
|
len = ti.length;
|
||||||
|
|
||||||
|
if (parse_tag (&p, &n, &ti))
|
||||||
|
goto bailout;
|
||||||
|
len -= ti.nhdr;
|
||||||
|
if (ti.tag == TAG_OBJECT_ID && ti.length == DIM(oid_encryptedData)
|
||||||
|
&& !memcmp (p, oid_encryptedData, DIM(oid_encryptedData)))
|
||||||
|
{
|
||||||
|
p += DIM(oid_encryptedData);
|
||||||
|
n -= DIM(oid_encryptedData);
|
||||||
|
len -= DIM(oid_encryptedData);
|
||||||
|
where = "bag.encryptedData";
|
||||||
|
if (parse_bag_encrypted_data (p, n, (p - buffer)))
|
||||||
|
goto bailout;
|
||||||
|
}
|
||||||
|
else if (ti.tag == TAG_OBJECT_ID && ti.length == DIM(oid_data)
|
||||||
|
&& !memcmp (p, oid_data, DIM(oid_data)))
|
||||||
|
{
|
||||||
|
p += DIM(oid_data);
|
||||||
|
n -= DIM(oid_data);
|
||||||
|
len -= DIM(oid_data);
|
||||||
|
return parse_bag_data (p, n, (p-buffer), pw);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
log_info ( "unknown bag type - skipped\n");
|
||||||
|
|
||||||
|
if (len < 0 || len > n)
|
||||||
|
goto bailout;
|
||||||
|
p += len;
|
||||||
|
n -= len;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
bailout:
|
||||||
|
log_error ("error at \"%s\", offset %u\n", where, (p - buffer));
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if 0 /* unser construction. */
|
||||||
|
/* Expect the RSA key parameters in KPARMS and a password in
|
||||||
|
PW. Create a PKCS structure from it and return it as well as the
|
||||||
|
length in R_LENGTH; return NULL in case of an error. */
|
||||||
|
unsigned char *
|
||||||
|
p12_build (GcryMPI *kparms, const char *pw, size_t *r_length)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
unsigned char *result;
|
||||||
|
size_t resultlen;
|
||||||
|
|
||||||
|
for (i=0; kparms[i]; i++)
|
||||||
|
;
|
||||||
|
if (i != 8)
|
||||||
|
{
|
||||||
|
log_error ("invalid paramters for p12_build\n");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
*r_length = resultlen;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef TEST
|
||||||
|
int
|
||||||
|
main (int argc, char **argv)
|
||||||
|
{
|
||||||
|
FILE *fp;
|
||||||
|
struct stat st;
|
||||||
|
char *buf;
|
||||||
|
size_t buflen;
|
||||||
|
GcryMPI *result;
|
||||||
|
|
||||||
|
if (argc != 3)
|
||||||
|
{
|
||||||
|
fprintf (stderr, "usage: testp12 file passphrase\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
gcry_control (GCRYCTL_DISABLE_SECMEM, NULL);
|
||||||
|
gcry_control (GCRYCTL_INITIALIZATION_FINISHED, NULL);
|
||||||
|
|
||||||
|
fp = fopen (argv[1], "rb");
|
||||||
|
if (!fp)
|
||||||
|
{
|
||||||
|
fprintf (stderr, "can't open `%s': %s\n", argv[1], strerror (errno));
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fstat (fileno(fp), &st))
|
||||||
|
{
|
||||||
|
fprintf (stderr, "can't stat `%s': %s\n", argv[1], strerror (errno));
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
buflen = st.st_size;
|
||||||
|
buf = malloc (buflen+1);
|
||||||
|
if (!buf || fread (buf, buflen, 1, fp) != 1)
|
||||||
|
{
|
||||||
|
fprintf (stderr, "error reading `%s': %s\n", argv[1], strerror (errno));
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
fclose (fp);
|
||||||
|
|
||||||
|
result = p12_parse (buf, buflen, argv[2]);
|
||||||
|
if (result)
|
||||||
|
{
|
||||||
|
int i, rc;
|
||||||
|
char *buf;
|
||||||
|
|
||||||
|
for (i=0; result[i]; i++)
|
||||||
|
{
|
||||||
|
rc = gcry_mpi_aprint (GCRYMPI_FMT_HEX, (void**)&buf,
|
||||||
|
NULL, result[i]);
|
||||||
|
if (rc)
|
||||||
|
printf ("%d: [error printing number: %s]\n",
|
||||||
|
i, gcry_strerror (rc));
|
||||||
|
else
|
||||||
|
{
|
||||||
|
printf ("%d: %s\n", i, buf);
|
||||||
|
gcry_free (buf);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
}
|
||||||
|
#endif /* TEST */
|
30
agent/minip12.h
Normal file
30
agent/minip12.h
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
/* minip12.h - Global definitions for the minimal pkcs-12 implementation.
|
||||||
|
* Copyright (C) 2002 Free Software Foundation, Inc.
|
||||||
|
*
|
||||||
|
* This file is part of GnuPG.
|
||||||
|
*
|
||||||
|
* GnuPG is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* GnuPG is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef MINIP12_H
|
||||||
|
#define MINIP12_H
|
||||||
|
|
||||||
|
#include <gcrypt.h>
|
||||||
|
|
||||||
|
GcryMPI *p12_parse (const unsigned char *buffer, size_t length,
|
||||||
|
const char *pw);
|
||||||
|
|
||||||
|
|
||||||
|
#endif /*MINIP12_H*/
|
@ -1,4 +1,4 @@
|
|||||||
/* protect-tool.c - A tool to text the secret key protection
|
/* protect-tool.c - A tool to test the secret key protection
|
||||||
* Copyright (C) 2002 Free Software Foundation, Inc.
|
* Copyright (C) 2002 Free Software Foundation, Inc.
|
||||||
*
|
*
|
||||||
* This file is part of GnuPG.
|
* This file is part of GnuPG.
|
||||||
@ -34,6 +34,7 @@
|
|||||||
|
|
||||||
#define JNLIB_NEED_LOG_LOGV
|
#define JNLIB_NEED_LOG_LOGV
|
||||||
#include "agent.h"
|
#include "agent.h"
|
||||||
|
#include "minip12.h"
|
||||||
|
|
||||||
#define N_(a) a
|
#define N_(a) a
|
||||||
#define _(a) a
|
#define _(a) a
|
||||||
@ -53,8 +54,20 @@ enum cmd_and_opt_values
|
|||||||
oShowShadowInfo,
|
oShowShadowInfo,
|
||||||
oShowKeygrip,
|
oShowKeygrip,
|
||||||
|
|
||||||
|
oP12Import,
|
||||||
|
|
||||||
aTest };
|
aTest };
|
||||||
|
|
||||||
|
struct rsa_secret_key_s
|
||||||
|
{
|
||||||
|
MPI n; /* public modulus */
|
||||||
|
MPI e; /* public exponent */
|
||||||
|
MPI d; /* exponent */
|
||||||
|
MPI p; /* prime p. */
|
||||||
|
MPI q; /* prime q. */
|
||||||
|
MPI u; /* inverse of p mod q. */
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
static int opt_armor;
|
static int opt_armor;
|
||||||
static const char *passphrase = "abc";
|
static const char *passphrase = "abc";
|
||||||
@ -65,13 +78,14 @@ static ARGPARSE_OPTS opts[] = {
|
|||||||
|
|
||||||
{ oVerbose, "verbose", 0, "verbose" },
|
{ oVerbose, "verbose", 0, "verbose" },
|
||||||
{ oArmor, "armor", 0, "write output in advanced format" },
|
{ oArmor, "armor", 0, "write output in advanced format" },
|
||||||
{ oPassphrase, "passphrase", 2, "|STRING| Use passphrase STRING" },
|
{ oPassphrase, "passphrase", 2, "|STRING|use passphrase STRING" },
|
||||||
{ oProtect, "protect", 256, "protect a private key"},
|
{ oProtect, "protect", 256, "protect a private key"},
|
||||||
{ oUnprotect, "unprotect", 256, "unprotect a private key"},
|
{ oUnprotect, "unprotect", 256, "unprotect a private key"},
|
||||||
{ oShadow, "shadow", 256, "create a shadow entry for a priblic key"},
|
{ oShadow, "shadow", 256, "create a shadow entry for a priblic key"},
|
||||||
{ oShowShadowInfo, "show-shadow-info", 256, "return the shadow info"},
|
{ oShowShadowInfo, "show-shadow-info", 256, "return the shadow info"},
|
||||||
{ oShowKeygrip, "show-keygrip", 256, " show the \"keygrip\""},
|
{ oShowKeygrip, "show-keygrip", 256, "show the \"keygrip\""},
|
||||||
|
|
||||||
|
{ oP12Import, "p12-import", 256, "import a PKCS-12 encoded private key"},
|
||||||
{0}
|
{0}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -135,6 +149,25 @@ my_gcry_logger (void *dummy, int level, const char *fmt, va_list arg_ptr)
|
|||||||
log_logv (level, fmt, arg_ptr);
|
log_logv (level, fmt, arg_ptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* static void */
|
||||||
|
/* print_mpi (const char *text, GcryMPI a) */
|
||||||
|
/* { */
|
||||||
|
/* char *buf; */
|
||||||
|
/* void *bufaddr = &buf; */
|
||||||
|
/* int rc; */
|
||||||
|
|
||||||
|
/* rc = gcry_mpi_aprint (GCRYMPI_FMT_HEX, bufaddr, NULL, a); */
|
||||||
|
/* if (rc) */
|
||||||
|
/* log_info ("%s: [error printing number: %s]\n", text, gcry_strerror (rc)); */
|
||||||
|
/* else */
|
||||||
|
/* { */
|
||||||
|
/* log_info ("%s: %s\n", text, buf); */
|
||||||
|
/* gcry_free (buf); */
|
||||||
|
/* } */
|
||||||
|
/* } */
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
static unsigned char *
|
static unsigned char *
|
||||||
make_canonical (const char *fname, const char *buf, size_t buflen)
|
make_canonical (const char *fname, const char *buf, size_t buflen)
|
||||||
@ -185,14 +218,13 @@ make_advanced (const unsigned char *buf, size_t buflen)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static unsigned char *
|
static char *
|
||||||
read_key (const char *fname)
|
read_file (const char *fname, size_t *r_length)
|
||||||
{
|
{
|
||||||
FILE *fp;
|
FILE *fp;
|
||||||
struct stat st;
|
struct stat st;
|
||||||
char *buf;
|
char *buf;
|
||||||
size_t buflen;
|
size_t buflen;
|
||||||
unsigned char *key;
|
|
||||||
|
|
||||||
fp = fopen (fname, "rb");
|
fp = fopen (fname, "rb");
|
||||||
if (!fp)
|
if (!fp)
|
||||||
@ -219,6 +251,19 @@ read_key (const char *fname)
|
|||||||
}
|
}
|
||||||
fclose (fp);
|
fclose (fp);
|
||||||
|
|
||||||
|
*r_length = buflen;
|
||||||
|
return buf;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static unsigned char *
|
||||||
|
read_key (const char *fname)
|
||||||
|
{
|
||||||
|
char *buf;
|
||||||
|
size_t buflen;
|
||||||
|
unsigned char *key;
|
||||||
|
|
||||||
|
buf = read_file (fname, &buflen);
|
||||||
key = make_canonical (fname, buf, buflen);
|
key = make_canonical (fname, buf, buflen);
|
||||||
xfree (buf);
|
xfree (buf);
|
||||||
return key;
|
return key;
|
||||||
@ -422,9 +467,211 @@ show_keygrip (const char *fname)
|
|||||||
putchar ('\n');
|
putchar ('\n');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int
|
||||||
|
rsa_key_check (struct rsa_secret_key_s *skey)
|
||||||
|
{
|
||||||
|
int err = 0;
|
||||||
|
MPI t = gcry_mpi_snew (0);
|
||||||
|
MPI t1 = gcry_mpi_snew (0);
|
||||||
|
MPI t2 = gcry_mpi_snew (0);
|
||||||
|
MPI phi = gcry_mpi_snew (0);
|
||||||
|
|
||||||
|
/* check that n == p * q */
|
||||||
|
gcry_mpi_mul (t, skey->p, skey->q);
|
||||||
|
if (gcry_mpi_cmp( t, skey->n) )
|
||||||
|
{
|
||||||
|
log_error ("RSA oops: n != p * q\n");
|
||||||
|
err++;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* check that p is less than q */
|
||||||
|
if (gcry_mpi_cmp (skey->p, skey->q) > 0)
|
||||||
|
{
|
||||||
|
GcryMPI tmp;
|
||||||
|
|
||||||
|
log_info ("swapping secret primes\n");
|
||||||
|
tmp = gcry_mpi_copy (skey->p);
|
||||||
|
gcry_mpi_set (skey->p, skey->q);
|
||||||
|
gcry_mpi_set (skey->q, tmp);
|
||||||
|
gcry_mpi_release (tmp);
|
||||||
|
/* and must recompute u of course */
|
||||||
|
gcry_mpi_invm (skey->u, skey->p, skey->q);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* check that e divides neither p-1 nor q-1 */
|
||||||
|
gcry_mpi_sub_ui (t, skey->p, 1 );
|
||||||
|
gcry_mpi_div (NULL, t, t, skey->e, 0);
|
||||||
|
if (!gcry_mpi_cmp_ui( t, 0) )
|
||||||
|
{
|
||||||
|
log_error ("RSA oops: e divides p-1\n");
|
||||||
|
err++;
|
||||||
|
}
|
||||||
|
gcry_mpi_sub_ui (t, skey->q, 1);
|
||||||
|
gcry_mpi_div (NULL, t, t, skey->e, 0);
|
||||||
|
if (!gcry_mpi_cmp_ui( t, 0))
|
||||||
|
{
|
||||||
|
log_info ( "RSA oops: e divides q-1\n" );
|
||||||
|
err++;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* check that d is correct. */
|
||||||
|
gcry_mpi_sub_ui (t1, skey->p, 1);
|
||||||
|
gcry_mpi_sub_ui (t2, skey->q, 1);
|
||||||
|
gcry_mpi_mul (phi, t1, t2);
|
||||||
|
gcry_mpi_invm (t, skey->e, phi);
|
||||||
|
if (gcry_mpi_cmp (t, skey->d))
|
||||||
|
{ /* no: try universal exponent. */
|
||||||
|
gcry_mpi_gcd (t, t1, t2);
|
||||||
|
gcry_mpi_div (t, NULL, phi, t, 0);
|
||||||
|
gcry_mpi_invm (t, skey->e, t);
|
||||||
|
if (gcry_mpi_cmp (t, skey->d))
|
||||||
|
{
|
||||||
|
log_error ("RSA oops: bad secret exponent\n");
|
||||||
|
err++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* check for correctness of u */
|
||||||
|
gcry_mpi_invm (t, skey->p, skey->q);
|
||||||
|
if (gcry_mpi_cmp (t, skey->u))
|
||||||
|
{
|
||||||
|
log_info ( "RSA oops: bad u parameter\n");
|
||||||
|
err++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (err)
|
||||||
|
log_info ("RSA secret key check failed\n");
|
||||||
|
|
||||||
|
gcry_mpi_release (t);
|
||||||
|
gcry_mpi_release (t1);
|
||||||
|
gcry_mpi_release (t2);
|
||||||
|
gcry_mpi_release (phi);
|
||||||
|
|
||||||
|
return err? -1:0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void
|
||||||
|
import_p12_file (const char *fname)
|
||||||
|
{
|
||||||
|
char *buf;
|
||||||
|
unsigned char *result;
|
||||||
|
size_t buflen, resultlen;
|
||||||
|
int i;
|
||||||
|
int rc;
|
||||||
|
GcryMPI *kparms;
|
||||||
|
struct rsa_secret_key_s sk;
|
||||||
|
GcrySexp s_key;
|
||||||
|
unsigned char *key;
|
||||||
|
|
||||||
|
/* fixme: we should release some stuff on error */
|
||||||
|
|
||||||
|
buf = read_file (fname, &buflen);
|
||||||
|
if (!buf)
|
||||||
|
return;
|
||||||
|
|
||||||
|
kparms = p12_parse (buf, buflen, passphrase);
|
||||||
|
xfree (buf);
|
||||||
|
if (!kparms)
|
||||||
|
{
|
||||||
|
log_error ("error parsing or decrypting the PKCS-1 file\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for (i=0; kparms[i]; i++)
|
||||||
|
;
|
||||||
|
if (i != 8)
|
||||||
|
{
|
||||||
|
log_error ("invalid structure of private key\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* print_mpi (" n", kparms[0]); */
|
||||||
|
/* print_mpi (" e", kparms[1]); */
|
||||||
|
/* print_mpi (" d", kparms[2]); */
|
||||||
|
/* print_mpi (" p", kparms[3]); */
|
||||||
|
/* print_mpi (" q", kparms[4]); */
|
||||||
|
/* print_mpi ("dmp1", kparms[5]); */
|
||||||
|
/* print_mpi ("dmq1", kparms[6]); */
|
||||||
|
/* print_mpi (" u", kparms[7]); */
|
||||||
|
|
||||||
|
sk.n = kparms[0];
|
||||||
|
sk.e = kparms[1];
|
||||||
|
sk.d = kparms[2];
|
||||||
|
sk.q = kparms[3];
|
||||||
|
sk.p = kparms[4];
|
||||||
|
sk.u = kparms[7];
|
||||||
|
if (rsa_key_check (&sk))
|
||||||
|
return;
|
||||||
|
/* print_mpi (" n", sk.n); */
|
||||||
|
/* print_mpi (" e", sk.e); */
|
||||||
|
/* print_mpi (" d", sk.d); */
|
||||||
|
/* print_mpi (" p", sk.p); */
|
||||||
|
/* print_mpi (" q", sk.q); */
|
||||||
|
/* print_mpi (" u", sk.u); */
|
||||||
|
|
||||||
|
/* Create an S-expresion from the parameters. */
|
||||||
|
rc = gcry_sexp_build (&s_key, NULL,
|
||||||
|
"(private-key(rsa(n%m)(e%m)(d%m)(p%m)(q%m)(u%m)))",
|
||||||
|
sk.n, sk.e, sk.d, sk.p, sk.q, sk.u, NULL);
|
||||||
|
for (i=0; i < 8; i++)
|
||||||
|
gcry_mpi_release (kparms[i]);
|
||||||
|
gcry_free (kparms);
|
||||||
|
if (rc)
|
||||||
|
{
|
||||||
|
log_error ("failed to created S-expression from key: %s\n",
|
||||||
|
gcry_strerror (rc));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Compute the keygrip. */
|
||||||
|
{
|
||||||
|
unsigned char grip[20];
|
||||||
|
if (!gcry_pk_get_keygrip (s_key, grip))
|
||||||
|
{
|
||||||
|
log_error ("can't calculate keygrip\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
log_info ("keygrip: ");
|
||||||
|
for (i=0; i < 20; i++)
|
||||||
|
log_printf ("%02X", grip[i]);
|
||||||
|
log_printf ("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
/* convert to canonical encoding */
|
||||||
|
buflen = gcry_sexp_sprint (s_key, GCRYSEXP_FMT_CANON, NULL, 0);
|
||||||
|
assert (buflen);
|
||||||
|
key = gcry_xmalloc_secure (buflen);
|
||||||
|
buflen = gcry_sexp_sprint (s_key, GCRYSEXP_FMT_CANON, key, buflen);
|
||||||
|
assert (buflen);
|
||||||
|
gcry_sexp_release (s_key);
|
||||||
|
|
||||||
|
|
||||||
|
rc = agent_protect (key, passphrase, &result, &resultlen);
|
||||||
|
xfree (key);
|
||||||
|
if (rc)
|
||||||
|
{
|
||||||
|
log_error ("protecting the key failed: %s\n", gnupg_strerror (rc));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (opt_armor)
|
||||||
|
{
|
||||||
|
char *p = make_advanced (result, resultlen);
|
||||||
|
xfree (result);
|
||||||
|
if (!p)
|
||||||
|
return;
|
||||||
|
result = p;
|
||||||
|
resultlen = strlen (p);
|
||||||
|
}
|
||||||
|
|
||||||
|
fwrite (result, resultlen, 1, stdout);
|
||||||
|
xfree (result);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
int
|
int
|
||||||
main (int argc, char **argv )
|
main (int argc, char **argv )
|
||||||
{
|
{
|
||||||
@ -461,6 +708,7 @@ main (int argc, char **argv )
|
|||||||
case oShadow: cmd = oShadow; break;
|
case oShadow: cmd = oShadow; break;
|
||||||
case oShowShadowInfo: cmd = oShowShadowInfo; break;
|
case oShowShadowInfo: cmd = oShowShadowInfo; break;
|
||||||
case oShowKeygrip: cmd = oShowKeygrip; break;
|
case oShowKeygrip: cmd = oShowKeygrip; break;
|
||||||
|
case oP12Import: cmd = oP12Import; break;
|
||||||
|
|
||||||
case oPassphrase: passphrase = pargs.r.ret_str; break;
|
case oPassphrase: passphrase = pargs.r.ret_str; break;
|
||||||
|
|
||||||
@ -483,6 +731,8 @@ main (int argc, char **argv )
|
|||||||
show_shadow_info (*argv);
|
show_shadow_info (*argv);
|
||||||
else if (cmd == oShowKeygrip)
|
else if (cmd == oShowKeygrip)
|
||||||
show_keygrip (*argv);
|
show_keygrip (*argv);
|
||||||
|
else if (cmd == oP12Import)
|
||||||
|
import_p12_file (*argv);
|
||||||
else
|
else
|
||||||
show_file (*argv);
|
show_file (*argv);
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user