mirror of
git://git.gnupg.org/gnupg.git
synced 2024-12-22 10:19:57 +01:00
common: New module to compute openpgp fingerprints
* common/openpgp-fpr.c: New. * common/Makefile.am (common_sources): Add it. -- This function is targeted to handle keys on smartcards. Signed-off-by: Werner Koch <wk@gnupg.org> (cherry picked from commit 2f2bdd9c0894eb43f719da8b529b4c7a46f742a0) Signed-off-by: Werner Koch <wk@gnupg.org>
This commit is contained in:
parent
c825117c5f
commit
f3c98b8cb5
@ -98,6 +98,7 @@ common_sources = \
|
||||
name-value.c name-value.h \
|
||||
recsel.c recsel.h \
|
||||
ksba-io-support.c ksba-io-support.h \
|
||||
openpgp-fpr.c \
|
||||
compliance.c compliance.h
|
||||
|
||||
|
||||
|
283
common/openpgp-fpr.c
Normal file
283
common/openpgp-fpr.c
Normal file
@ -0,0 +1,283 @@
|
||||
/* openpgp-fpr.c - OpenPGP Fingerprint computation
|
||||
* Copyright (C) 2021 g10 Code GmbH
|
||||
*
|
||||
* This file is part of GnuPG.
|
||||
*
|
||||
* This file is free software; you can redistribute it and/or modify
|
||||
* it under the terms of either
|
||||
*
|
||||
* - the GNU Lesser General Public License as published by the Free
|
||||
* Software Foundation; either version 3 of the License, or (at
|
||||
* your option) any later version.
|
||||
*
|
||||
* or
|
||||
*
|
||||
* - 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.
|
||||
*
|
||||
* or both in parallel, as here.
|
||||
*
|
||||
* This file 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, see <https://www.gnu.org/licenses/>.
|
||||
* SPDX-License-Identifier: (LGPL-3.0-or-later OR GPL-2.0-or-later)
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#include "util.h"
|
||||
#include "openpgpdefs.h"
|
||||
|
||||
/* Count the number of bits, assuming the A represents an unsigned big
|
||||
* integer of length LEN bytes. */
|
||||
static unsigned int
|
||||
count_bits (const unsigned char *a, size_t len)
|
||||
{
|
||||
unsigned int n = len * 8;
|
||||
int i;
|
||||
|
||||
for (; len && !*a; len--, a++, n -=8)
|
||||
;
|
||||
if (len)
|
||||
{
|
||||
for (i=7; i && !(*a & (1<<i)); i--)
|
||||
n--;
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
/* Variant of count_bits for simple octet strings. */
|
||||
static unsigned int
|
||||
count_sos_bits (const unsigned char *a, size_t len)
|
||||
{
|
||||
unsigned int n = len * 8;
|
||||
int i;
|
||||
|
||||
if (len == 0 || *a == 0)
|
||||
return n;
|
||||
|
||||
for (i=7; i && !(*a & (1<<i)); i--)
|
||||
n--;
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
|
||||
gpg_error_t
|
||||
compute_openpgp_fpr (int keyversion, int pgpalgo, unsigned long timestamp,
|
||||
gcry_buffer_t *iov, int iovcnt,
|
||||
unsigned char *result, unsigned int *r_resultlen)
|
||||
{
|
||||
gpg_error_t err;
|
||||
int hashalgo;
|
||||
unsigned char prefix[15];
|
||||
size_t n;
|
||||
int i;
|
||||
|
||||
if (r_resultlen)
|
||||
*r_resultlen = 0;
|
||||
|
||||
if (iovcnt < 2)
|
||||
return gpg_error (GPG_ERR_INV_ARG);
|
||||
|
||||
/* Note that iov[0] is reserved. */
|
||||
for (n=0, i=1; i < iovcnt; i++)
|
||||
n += iov[i].len;
|
||||
|
||||
i = 0;
|
||||
if (keyversion == 5)
|
||||
{
|
||||
hashalgo = GCRY_MD_SHA256;
|
||||
n += 10; /* Add the prefix length. */
|
||||
prefix[i++] = 0x9a;
|
||||
prefix[i++] = (n >> 24);
|
||||
prefix[i++] = (n >> 16);
|
||||
}
|
||||
else if (keyversion == 4)
|
||||
{
|
||||
hashalgo = GCRY_MD_SHA1;
|
||||
n += 6; /* Add the prefix length. */
|
||||
prefix[i++] = 0x99;
|
||||
}
|
||||
else
|
||||
return gpg_error (GPG_ERR_UNKNOWN_VERSION);
|
||||
|
||||
prefix[i++] = (n >> 8);
|
||||
prefix[i++] = n;
|
||||
prefix[i++] = keyversion;
|
||||
prefix[i++] = (timestamp >> 24);
|
||||
prefix[i++] = (timestamp >> 16);
|
||||
prefix[i++] = (timestamp >> 8);
|
||||
prefix[i++] = (timestamp);
|
||||
prefix[i++] = pgpalgo;
|
||||
if (keyversion == 5)
|
||||
{
|
||||
prefix[i++] = ((n-10) >> 24);
|
||||
prefix[i++] = ((n-10) >> 16);
|
||||
prefix[i++] = ((n-10) >> 8);
|
||||
prefix[i++] = (n-10);
|
||||
}
|
||||
log_assert (i <= sizeof prefix);
|
||||
/* The first element is reserved for our use; set it. */
|
||||
iov[0].size = 0;
|
||||
iov[0].off = 0;
|
||||
iov[0].len = i;
|
||||
iov[0].data = prefix;
|
||||
|
||||
/* for (i=0; i < iovcnt; i++) */
|
||||
/* log_printhex (iov[i].data, iov[i].len, "cmpfpr i=%d: ", i); */
|
||||
|
||||
err = gcry_md_hash_buffers (hashalgo, 0, result, iov, iovcnt);
|
||||
/* log_printhex (result, 20, "fingerpint: "); */
|
||||
|
||||
/* Better clear the first element because it was set by us. */
|
||||
iov[0].size = 0;
|
||||
iov[0].off = 0;
|
||||
iov[0].len = 0;
|
||||
iov[0].data = NULL;
|
||||
|
||||
if (!err && r_resultlen)
|
||||
*r_resultlen = (hashalgo == GCRY_MD_SHA1)? 20 : 32;
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
gpg_error_t
|
||||
compute_openpgp_fpr_rsa (int keyversion, unsigned long timestamp,
|
||||
const unsigned char *m, unsigned int mlen,
|
||||
const unsigned char *e, unsigned int elen,
|
||||
unsigned char *result, unsigned int *r_resultlen)
|
||||
{
|
||||
gcry_buffer_t iov[5] = { {0} };
|
||||
unsigned char nbits_m[2], nbits_e[2];
|
||||
unsigned int n;
|
||||
|
||||
/* Strip leading zeroes. */
|
||||
for (; mlen && !*m; mlen--, m++)
|
||||
;
|
||||
for (; elen && !*e; elen--, e++)
|
||||
;
|
||||
|
||||
/* Count bits. */
|
||||
n = count_bits (m, mlen);
|
||||
nbits_m[0] = n >> 8;
|
||||
nbits_m[1] = n;
|
||||
|
||||
n = count_bits (e, elen);
|
||||
nbits_e[0] = n >> 8;
|
||||
nbits_e[1] = n;
|
||||
|
||||
/* Put parms into the array. Note that iov[0] is reserved. */
|
||||
iov[1].len = 2;
|
||||
iov[1].data = nbits_m;
|
||||
iov[2].len = mlen;
|
||||
iov[2].data = (void*)m;
|
||||
iov[3].len = 2;
|
||||
iov[3].data = nbits_e;
|
||||
iov[4].len = elen;
|
||||
iov[4].data = (void*)e;
|
||||
|
||||
return compute_openpgp_fpr (keyversion, PUBKEY_ALGO_RSA, timestamp,
|
||||
iov, 5, result, r_resultlen);
|
||||
}
|
||||
|
||||
|
||||
/* Determine KDF hash algorithm and KEK encryption algorithm by CURVE.
|
||||
* The returned buffer has a length of 4.
|
||||
* Note: This needs to be kept in sync with the table in g10/ecdh.c */
|
||||
static const unsigned char*
|
||||
default_ecdh_params (unsigned int nbits)
|
||||
{
|
||||
/* See RFC-6637 for those constants.
|
||||
0x03: Number of bytes
|
||||
0x01: Version for this parameter format
|
||||
KEK digest algorithm
|
||||
KEK cipher algorithm
|
||||
*/
|
||||
if (nbits <= 256)
|
||||
return (const unsigned char*)"\x03\x01\x08\x07";
|
||||
else if (nbits <= 384)
|
||||
return (const unsigned char*)"\x03\x01\x09\x09";
|
||||
else
|
||||
return (const unsigned char*)"\x03\x01\x0a\x09";
|
||||
}
|
||||
|
||||
|
||||
gpg_error_t
|
||||
compute_openpgp_fpr_ecc (int keyversion, unsigned long timestamp,
|
||||
const char *curvename, int for_encryption,
|
||||
const unsigned char *q, unsigned int qlen,
|
||||
const unsigned char *kdf, unsigned int kdflen,
|
||||
unsigned char *result, unsigned int *r_resultlen)
|
||||
{
|
||||
gpg_error_t err;
|
||||
const char *curveoidstr;
|
||||
gcry_mpi_t curveoid = NULL;
|
||||
unsigned int curvebits;
|
||||
int pgpalgo;
|
||||
const unsigned char *oidraw;
|
||||
size_t oidrawlen;
|
||||
gcry_buffer_t iov[5] = { {0} };
|
||||
unsigned int iovlen;
|
||||
unsigned char nbits_q[2];
|
||||
unsigned int n;
|
||||
|
||||
curveoidstr = openpgp_curve_to_oid (curvename, &curvebits, &pgpalgo);
|
||||
err = openpgp_oid_from_str (curveoidstr, &curveoid);
|
||||
if (err)
|
||||
goto leave;
|
||||
oidraw = gcry_mpi_get_opaque (curveoid, &n);
|
||||
if (!oidraw)
|
||||
{
|
||||
err = gpg_error_from_syserror ();
|
||||
goto leave;
|
||||
}
|
||||
oidrawlen = (n+7)/8;
|
||||
|
||||
/* If the curve does not enforce a certain algorithm, we use the
|
||||
* for_encryption flag to decide which algo to use. */
|
||||
if (!pgpalgo)
|
||||
pgpalgo = for_encryption? PUBKEY_ALGO_ECDH : PUBKEY_ALGO_ECDSA;
|
||||
|
||||
/* Count bits. */
|
||||
n = count_sos_bits (q, qlen);
|
||||
nbits_q[0] = n >> 8;
|
||||
nbits_q[1] = n;
|
||||
|
||||
/* Put parms into the array. Note that iov[0] is reserved. */
|
||||
iov[1].len = oidrawlen;
|
||||
iov[1].data = (void*)oidraw;
|
||||
iov[2].len = 2;
|
||||
iov[2].data = nbits_q;
|
||||
iov[3].len = qlen;
|
||||
iov[3].data = (void*)q;
|
||||
iovlen = 4;
|
||||
if (pgpalgo == PUBKEY_ALGO_ECDH)
|
||||
{
|
||||
if (!kdf || !kdflen || !kdf[0])
|
||||
{
|
||||
/* No KDF givem - use the default. */
|
||||
kdflen = 4;
|
||||
kdf = default_ecdh_params (curvebits);
|
||||
}
|
||||
iov[4].len = kdflen;
|
||||
iov[4].data = (void*)kdf;
|
||||
iovlen++;
|
||||
}
|
||||
|
||||
err = compute_openpgp_fpr (keyversion, pgpalgo, timestamp,
|
||||
iov, iovlen, result, r_resultlen);
|
||||
|
||||
leave:
|
||||
gcry_mpi_release (curveoid);
|
||||
return err;
|
||||
}
|
@ -205,4 +205,26 @@ compress_algo_t;
|
||||
#define OPENPGP_MAX_NENC 2 /* Maximum number of encryption parameters. */
|
||||
|
||||
|
||||
/*-- openpgp-fpr.c --*/
|
||||
gpg_error_t compute_openpgp_fpr (int keyversion, int pgpalgo,
|
||||
unsigned long timestamp,
|
||||
gcry_buffer_t *iov, int iovcnt,
|
||||
unsigned char *result,
|
||||
unsigned int *r_resultlen);
|
||||
gpg_error_t compute_openpgp_fpr_rsa (int keyversion,
|
||||
unsigned long timestamp,
|
||||
const unsigned char *m, unsigned int mlen,
|
||||
const unsigned char *e, unsigned int elen,
|
||||
unsigned char *result,
|
||||
unsigned int *r_resultlen);
|
||||
gpg_error_t compute_openpgp_fpr_ecc (int keyversion,
|
||||
unsigned long timestamp,
|
||||
const char *curvename, int for_encryption,
|
||||
const unsigned char *q, unsigned int qlen,
|
||||
const unsigned char *kdf,
|
||||
unsigned int kdflen,
|
||||
unsigned char *result,
|
||||
unsigned int *r_resultlen);
|
||||
|
||||
|
||||
#endif /*GNUPG_COMMON_OPENPGPDEFS_H*/
|
||||
|
Loading…
x
Reference in New Issue
Block a user