/* keyid.c - key ID and fingerprint handling * Copyright (C) 1998, 1999, 2000, 2001, 2003, * 2004, 2006 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, * USA. */ #include #include #include #include #include #include #include #include "gpg.h" #include "util.h" #include "main.h" #include "packet.h" #include "options.h" #include "keydb.h" #include "i18n.h" int pubkey_letter( int algo ) { switch( algo ) { case PUBKEY_ALGO_RSA: return 'R' ; case PUBKEY_ALGO_RSA_E: return 'r' ; case PUBKEY_ALGO_RSA_S: return 's' ; case PUBKEY_ALGO_ELGAMAL_E: return 'g'; case PUBKEY_ALGO_ELGAMAL: return 'G' ; case PUBKEY_ALGO_DSA: return 'D' ; default: return '?'; } } /* This function is useful for v4 fingerprints and v3 or v4 key signing. */ void hash_public_key( gcry_md_hd_t md, PKT_public_key *pk ) { unsigned int n = 6; unsigned int nn[PUBKEY_MAX_NPKEY]; byte *pp[PUBKEY_MAX_NPKEY]; int i; size_t nbits, nbytes; int npkey = pubkey_get_npkey (pk->pubkey_algo); /* Two extra bytes for the expiration date in v3 */ if(pk->version<4) n+=2; if (npkey==0 && pk->pkey[0] && gcry_mpi_get_flag (pk->pkey[0], GCRYMPI_FLAG_OPAQUE)) { pp[0] = gcry_mpi_get_opaque (pk->pkey[0], &nbits); nn[0] = (nbits+7)/8; n+=nn[0]; } else for(i=0; i < npkey; i++ ) { if (gcry_mpi_print (GCRYMPI_FMT_PGP, NULL, 0, &nbytes, pk->pkey[i])) BUG (); pp[i] = xmalloc (nbytes); if (gcry_mpi_print (GCRYMPI_FMT_PGP, pp[i], nbytes, &nbytes, pk->pkey[i])) BUG (); nn[i] = nbytes; n += nn[i]; } gcry_md_putc ( md, 0x99 ); /* ctb */ /* What does it mean if n is greater than than 0xFFFF ? */ gcry_md_putc ( md, n >> 8 ); /* 2 byte length header */ gcry_md_putc ( md, n ); gcry_md_putc ( md, pk->version ); gcry_md_putc ( md, pk->timestamp >> 24 ); gcry_md_putc ( md, pk->timestamp >> 16 ); gcry_md_putc ( md, pk->timestamp >> 8 ); gcry_md_putc ( md, pk->timestamp ); if(pk->version<4) { u16 days=0; if(pk->expiredate) days=(u16)((pk->expiredate - pk->timestamp) / 86400L); gcry_md_putc ( md, days >> 8 ); gcry_md_putc ( md, days ); } gcry_md_putc ( md, pk->pubkey_algo ); if(npkey==0 && pk->pkey[0] && gcry_mpi_get_flag (pk->pkey[0], GCRYMPI_FLAG_OPAQUE)) { gcry_md_write (md, pp[0], nn[0]); } else for(i=0; i < npkey; i++ ) { gcry_md_write ( md, pp[i], nn[i] ); xfree(pp[i]); } } static gcry_md_hd_t do_fingerprint_md( PKT_public_key *pk ) { gcry_md_hd_t md; if (gcry_md_open (&md, DIGEST_ALGO_SHA1, 0)) BUG (); hash_public_key(md,pk); gcry_md_final( md ); return md; } static gcry_md_hd_t do_fingerprint_md_sk( PKT_secret_key *sk ) { PKT_public_key pk; int npkey = pubkey_get_npkey( sk->pubkey_algo ); /* npkey is correct! */ int i; if(npkey==0) return NULL; pk.pubkey_algo = sk->pubkey_algo; pk.version = sk->version; pk.timestamp = sk->timestamp; pk.expiredate = sk->expiredate; pk.pubkey_algo = sk->pubkey_algo; for( i=0; i < npkey; i++ ) pk.pkey[i] = sk->skey[i]; return do_fingerprint_md( &pk ); } u32 v3_keyid (gcry_mpi_t a, u32 *ki) { byte *buffer; size_t nbytes; if (gcry_mpi_print (GCRYMPI_FMT_USG, NULL, 0, &nbytes, a )) BUG (); /* fixme: allocate it on the stack */ buffer = xmalloc (nbytes); if (gcry_mpi_print( GCRYMPI_FMT_USG, buffer, nbytes, NULL, a )) BUG (); if (nbytes < 8) /* oops */ ki[0] = ki[1] = 0; else { memcpy (ki+0, buffer+nbytes-8, 4); memcpy (ki+1, buffer+nbytes-4, 4); } xfree (buffer); return ki[1]; } size_t keystrlen(void) { switch(opt.keyid_format) { case KF_SHORT: return 8; case KF_LONG: return 16; case KF_0xSHORT: return 10; case KF_0xLONG: return 18; default: BUG(); } } const char * keystr(u32 *keyid) { static char keyid_str[19]; switch(opt.keyid_format) { case KF_SHORT: sprintf(keyid_str,"%08lX",(ulong)keyid[1]); break; case KF_LONG: if(keyid[0]) sprintf(keyid_str,"%08lX%08lX",(ulong)keyid[0],(ulong)keyid[1]); else sprintf(keyid_str,"%08lX",(ulong)keyid[1]); break; case KF_0xSHORT: sprintf(keyid_str,"0x%08lX",(ulong)keyid[1]); break; case KF_0xLONG: if(keyid[0]) sprintf(keyid_str,"0x%08lX%08lX",(ulong)keyid[0],(ulong)keyid[1]); else sprintf(keyid_str,"0x%08lX",(ulong)keyid[1]); break; default: BUG(); } return keyid_str; } const char * keystr_from_pk(PKT_public_key *pk) { keyid_from_pk(pk,NULL); return keystr(pk->keyid); } const char * keystr_from_sk(PKT_secret_key *sk) { keyid_from_sk(sk,NULL); return keystr(sk->keyid); } const char * keystr_from_desc(KEYDB_SEARCH_DESC *desc) { switch(desc->mode) { case KEYDB_SEARCH_MODE_LONG_KID: case KEYDB_SEARCH_MODE_SHORT_KID: return keystr(desc->u.kid); case KEYDB_SEARCH_MODE_FPR20: { u32 keyid[2]; keyid[0] = ((unsigned char)desc->u.fpr[12] << 24 | (unsigned char)desc->u.fpr[13] << 16 | (unsigned char)desc->u.fpr[14] << 8 | (unsigned char)desc->u.fpr[15]); keyid[1] = ((unsigned char)desc->u.fpr[16] << 24 | (unsigned char)desc->u.fpr[17] << 16 | (unsigned char)desc->u.fpr[18] << 8 | (unsigned char)desc->u.fpr[19]); return keystr(keyid); } case KEYDB_SEARCH_MODE_FPR16: return "?v3 fpr?"; default: BUG(); } } /**************** * Get the keyid from the secret key and put it into keyid * if this is not NULL. Return the 32 low bits of the keyid. */ u32 keyid_from_sk( PKT_secret_key *sk, u32 *keyid ) { u32 lowbits; u32 dummy_keyid[2]; if( !keyid ) keyid = dummy_keyid; if( sk->keyid[0] || sk->keyid[1] ) { keyid[0] = sk->keyid[0]; keyid[1] = sk->keyid[1]; lowbits = keyid[1]; } else if( sk->version < 4 ) { if( is_RSA(sk->pubkey_algo) ) { lowbits = (pubkey_get_npkey (sk->pubkey_algo) ? v3_keyid( sk->skey[0], keyid ) : 0); /* Take n. */ sk->keyid[0]=keyid[0]; sk->keyid[1]=keyid[1]; } else sk->keyid[0]=sk->keyid[1]=keyid[0]=keyid[1]=lowbits=0xFFFFFFFF; } else { const byte *dp; gcry_md_hd_t md; md = do_fingerprint_md_sk(sk); if(md) { dp = gcry_md_read (md, 0); keyid[0] = dp[12] << 24 | dp[13] << 16 | dp[14] << 8 | dp[15] ; keyid[1] = dp[16] << 24 | dp[17] << 16 | dp[18] << 8 | dp[19] ; lowbits = keyid[1]; gcry_md_close (md); sk->keyid[0] = keyid[0]; sk->keyid[1] = keyid[1]; } else sk->keyid[0]=sk->keyid[1]=keyid[0]=keyid[1]=lowbits=0xFFFFFFFF; } return lowbits; } /**************** * Get the keyid from the public key and put it into keyid * if this is not NULL. Return the 32 low bits of the keyid. */ u32 keyid_from_pk( PKT_public_key *pk, u32 *keyid ) { u32 lowbits; u32 dummy_keyid[2]; if( !keyid ) keyid = dummy_keyid; if( pk->keyid[0] || pk->keyid[1] ) { keyid[0] = pk->keyid[0]; keyid[1] = pk->keyid[1]; lowbits = keyid[1]; } else if( pk->version < 4 ) { if( is_RSA(pk->pubkey_algo) ) { lowbits = (pubkey_get_npkey (pk->pubkey_algo) ? v3_keyid ( pk->pkey[0], keyid ) : 0); /* From n. */ pk->keyid[0] = keyid[0]; pk->keyid[1] = keyid[1]; } else pk->keyid[0]=pk->keyid[1]=keyid[0]=keyid[1]=lowbits=0xFFFFFFFF; } else { const byte *dp; gcry_md_hd_t md; md = do_fingerprint_md(pk); if(md) { dp = gcry_md_read ( md, 0 ); keyid[0] = dp[12] << 24 | dp[13] << 16 | dp[14] << 8 | dp[15] ; keyid[1] = dp[16] << 24 | dp[17] << 16 | dp[18] << 8 | dp[19] ; lowbits = keyid[1]; gcry_md_close (md); pk->keyid[0] = keyid[0]; pk->keyid[1] = keyid[1]; } else pk->keyid[0]=pk->keyid[1]=keyid[0]=keyid[1]=lowbits=0xFFFFFFFF; } return lowbits; } /**************** * Get the keyid from the fingerprint. This function is simple for most * keys, but has to do a keylookup for old stayle keys. */ u32 keyid_from_fingerprint( const byte *fprint, size_t fprint_len, u32 *keyid ) { u32 dummy_keyid[2]; if( !keyid ) keyid = dummy_keyid; if( fprint_len != 20 ) { /* This is special as we have to lookup the key first */ PKT_public_key pk; int rc; memset( &pk, 0, sizeof pk ); rc = get_pubkey_byfprint( &pk, fprint, fprint_len ); if( rc ) { log_error("Oops: keyid_from_fingerprint: no pubkey\n"); keyid[0] = 0; keyid[1] = 0; } else keyid_from_pk( &pk, keyid ); } else { const byte *dp = fprint; keyid[0] = dp[12] << 24 | dp[13] << 16 | dp[14] << 8 | dp[15] ; keyid[1] = dp[16] << 24 | dp[17] << 16 | dp[18] << 8 | dp[19] ; } return keyid[1]; } u32 keyid_from_sig( PKT_signature *sig, u32 *keyid ) { if( keyid ) { keyid[0] = sig->keyid[0]; keyid[1] = sig->keyid[1]; } return sig->keyid[1]; } byte * namehash_from_uid(PKT_user_id *uid) { if(uid->namehash==NULL) { uid->namehash = xmalloc(20); if(uid->attrib_data) gcry_md_hash_buffer (GCRY_MD_RMD160, uid->namehash, uid->attrib_data, uid->attrib_len); else gcry_md_hash_buffer (GCRY_MD_RMD160, uid->namehash, uid->name, uid->len); } return uid->namehash; } /**************** * return the number of bits used in the pk */ unsigned nbits_from_pk( PKT_public_key *pk ) { return pubkey_nbits( pk->pubkey_algo, pk->pkey ); } /**************** * return the number of bits used in the sk */ unsigned nbits_from_sk( PKT_secret_key *sk ) { return pubkey_nbits( sk->pubkey_algo, sk->skey ); } static const char * mk_datestr (char *buffer, time_t atime) { struct tm *tp; if ( atime < 0 ) /* 32 bit time_t and after 2038-01-19 */ strcpy (buffer, "????" "-??" "-??"); /* mark this as invalid */ else { tp = gmtime (&atime); sprintf (buffer,"%04d-%02d-%02d", 1900+tp->tm_year, tp->tm_mon+1, tp->tm_mday ); } return buffer; } /**************** * return a string with the creation date of the pk * Note: this is alloced in a static buffer. * Format is: yyyy-mm-dd */ const char * datestr_from_pk( PKT_public_key *pk ) { static char buffer[11+5]; time_t atime = pk->timestamp; return mk_datestr (buffer, atime); } const char * datestr_from_sk( PKT_secret_key *sk ) { static char buffer[11+5]; time_t atime = sk->timestamp; return mk_datestr (buffer, atime); } const char * datestr_from_sig( PKT_signature *sig ) { static char buffer[11+5]; time_t atime = sig->timestamp; return mk_datestr (buffer, atime); } const char * expirestr_from_pk( PKT_public_key *pk ) { static char buffer[11+5]; time_t atime; if( !pk->expiredate ) return _("never "); atime = pk->expiredate; return mk_datestr (buffer, atime); } const char * expirestr_from_sk( PKT_secret_key *sk ) { static char buffer[11+5]; time_t atime; if( !sk->expiredate ) return _("never "); atime = sk->expiredate; return mk_datestr (buffer, atime); } const char * expirestr_from_sig( PKT_signature *sig ) { static char buffer[11+5]; time_t atime; if(!sig->expiredate) return _("never "); atime=sig->expiredate; return mk_datestr (buffer, atime); } const char * revokestr_from_pk( PKT_public_key *pk ) { static char buffer[11+5]; time_t atime; if(!pk->revoked.date) return _("never "); atime=pk->revoked.date; return mk_datestr (buffer, atime); } const char * usagestr_from_pk( PKT_public_key *pk ) { static char buffer[10]; int i = 0; unsigned int use = pk->pubkey_usage; if ( use & PUBKEY_USAGE_SIG ) buffer[i++] = 'S'; if ( use & PUBKEY_USAGE_CERT ) buffer[i++] = 'C'; if ( use & PUBKEY_USAGE_ENC ) buffer[i++] = 'E'; if ( (use & PUBKEY_USAGE_AUTH) ) buffer[i++] = 'A'; while (i < 4) buffer[i++] = ' '; buffer[i] = 0; return buffer; } const char * colon_strtime (u32 t) { if (!t) return ""; if (opt.fixed_list_mode) { static char buf[15]; sprintf (buf, "%lu", (ulong)t); return buf; } return strtimestamp(t); } const char * colon_datestr_from_pk (PKT_public_key *pk) { if (opt.fixed_list_mode) { static char buf[15]; sprintf (buf, "%lu", (ulong)pk->timestamp); return buf; } return datestr_from_pk (pk); } const char * colon_datestr_from_sk (PKT_secret_key *sk) { if (opt.fixed_list_mode) { static char buf[15]; sprintf (buf, "%lu", (ulong)sk->timestamp); return buf; } return datestr_from_sk (sk); } const char * colon_datestr_from_sig (PKT_signature *sig) { if (opt.fixed_list_mode) { static char buf[15]; sprintf (buf, "%lu", (ulong)sig->timestamp); return buf; } return datestr_from_sig (sig); } const char * colon_expirestr_from_sig (PKT_signature *sig) { if(!sig->expiredate) return ""; if (opt.fixed_list_mode) { static char buf[15]; sprintf (buf, "%lu", (ulong)sig->expiredate); return buf; } return expirestr_from_sig (sig); } /**************** . * Return a byte array with the fingerprint for the given PK/SK * The length of the array is returned in ret_len. Caller must free * the array or provide an array of length MAX_FINGERPRINT_LEN. */ byte * fingerprint_from_pk( PKT_public_key *pk, byte *array, size_t *ret_len ) { byte *buf; const byte *dp; size_t len, nbytes; int i; if ( pk->version < 4 ) { if ( is_RSA(pk->pubkey_algo) ) { /* RSA in version 3 packets is special. */ gcry_md_hd_t md; if (gcry_md_open (&md, DIGEST_ALGO_MD5, 0)) BUG (); if ( pubkey_get_npkey (pk->pubkey_algo) > 1 ) { for (i=0; i < 2; i++) { if (gcry_mpi_print (GCRYMPI_FMT_USG, NULL, 0, &nbytes, pk->pkey[i])) BUG (); /* fixme: Better allocate BUF on the stack */ buf = xmalloc (nbytes); if (gcry_mpi_print (GCRYMPI_FMT_USG, buf, nbytes, NULL, pk->pkey[i])) BUG (); gcry_md_write (md, buf, nbytes); xfree (buf); } } gcry_md_final (md); if (!array) array = xmalloc (16); len = 16; memcpy (array, gcry_md_read (md, DIGEST_ALGO_MD5), 16); gcry_md_close(md); } else { if (!array) array = xmalloc(16); len = 16; memset (array,0,16); } } else { gcry_md_hd_t md; md = do_fingerprint_md(pk); dp = gcry_md_read( md, 0 ); len = gcry_md_get_algo_dlen (gcry_md_get_algo (md)); assert( len <= MAX_FINGERPRINT_LEN ); if (!array) array = xmalloc ( len ); memcpy (array, dp, len ); pk->keyid[0] = dp[12] << 24 | dp[13] << 16 | dp[14] << 8 | dp[15] ; pk->keyid[1] = dp[16] << 24 | dp[17] << 16 | dp[18] << 8 | dp[19] ; gcry_md_close( md); } *ret_len = len; return array; } byte * fingerprint_from_sk( PKT_secret_key *sk, byte *array, size_t *ret_len ) { byte *buf; const char *dp; size_t len, nbytes; int i; if (sk->version < 4) { if ( is_RSA(sk->pubkey_algo) ) { /* RSA in version 3 packets is special. */ gcry_md_hd_t md; if (gcry_md_open (&md, DIGEST_ALGO_MD5, 0)) BUG (); if (pubkey_get_npkey( sk->pubkey_algo ) > 1) { for (i=0; i < 2; i++) { if (gcry_mpi_print (GCRYMPI_FMT_USG, NULL, 0, &nbytes, sk->skey[i])) BUG (); /* fixme: Better allocate BUF on the stack */ buf = xmalloc (nbytes); if (gcry_mpi_print (GCRYMPI_FMT_USG, buf, nbytes, NULL, sk->skey[i])) BUG (); gcry_md_write (md, buf, nbytes); xfree (buf); } } gcry_md_final(md); if (!array) array = xmalloc (16); len = 16; memcpy (array, gcry_md_read (md, DIGEST_ALGO_MD5), 16); gcry_md_close (md); } else { if (!array) array = xmalloc (16); len=16; memset (array,0,16); } } else { gcry_md_hd_t md; md = do_fingerprint_md_sk(sk); if (md) { dp = gcry_md_read ( md, 0 ); len = gcry_md_get_algo_dlen ( gcry_md_get_algo (md) ); assert ( len <= MAX_FINGERPRINT_LEN ); if (!array) array = xmalloc( len ); memcpy (array, dp, len); gcry_md_close (md); } else { len = MAX_FINGERPRINT_LEN; if (!array) array = xmalloc (len); memset (array, 0, len); } } *ret_len = len; return array; } /* Create a serialno/fpr string from the serial number and the secret key. Caller must free the returned string. There is no error return. */ char * serialno_and_fpr_from_sk (const unsigned char *sn, size_t snlen, PKT_secret_key *sk) { unsigned char fpr[MAX_FINGERPRINT_LEN]; size_t fprlen; char *buffer, *p; int i; fingerprint_from_sk (sk, fpr, &fprlen); buffer = p = xmalloc (snlen*2 + 1 + fprlen*2 + 1); for (i=0; i < snlen; i++, p+=2) sprintf (p, "%02X", sn[i]); *p++ = '/'; for (i=0; i < fprlen; i++, p+=2) sprintf (p, "%02X", fpr[i]); *p = 0; return buffer; }