static int keydb_idx_parse( cdk_stream_t inp, key_idx_t * r_idx ) { key_idx_t idx; byte buf[4]; int i; if( !inp || !r_idx ) return CDK_Inv_Value; idx = cdk_calloc( 1, sizeof * idx ); if( !idx ) return CDK_Out_Of_Core; while( !cdk_stream_eof( inp ) ) { i = cdk_stream_read( inp, buf, 4 ); if( i == CDK_EOF ) break; idx->offset = _cdk_buftou32( buf ); cdk_stream_read( inp, buf, 4 ); idx->keyid[0] = _cdk_buftou32( buf ); cdk_stream_read( inp, buf, 4 ); idx->keyid[1] = _cdk_buftou32( buf ); cdk_stream_read( inp, idx->fpr, 20 ); #if 0 _cdk_log_debug( "%08lu: keyid=%08lX fpr=", idx->offset,idx->keyid[1] ); for( i = 0; i < 20; i++ ) _cdk_log_debug( "%02X", idx->fpr[i] ); _cdk_log_debug( "\n" ); #endif break; } *r_idx = idx; return cdk_stream_eof( inp )? CDK_EOF : 0; }
/** * cdk_pk_get_keyid: * @pk: the public key * @keyid: buffer to store the key ID * * Calculate the key ID of the given public key. **/ u32 cdk_pk_get_keyid (cdk_pubkey_t pk, u32 *keyid) { u32 lowbits = 0; byte buf[24]; if (pk && (!pk->keyid[0] || !pk->keyid[1])) { if (pk->version < 4 && is_RSA (pk->pubkey_algo)) { byte p[MAX_MPI_BYTES]; size_t n; gcry_mpi_print (GCRYMPI_FMT_USG, p, MAX_MPI_BYTES, &n, pk->mpi[0]); pk->keyid[0] = p[n-8] << 24 | p[n-7] << 16 | p[n-6] << 8 | p[n-5]; pk->keyid[1] = p[n-4] << 24 | p[n-3] << 16 | p[n-2] << 8 | p[n-1]; } else if (pk->version == 4) { cdk_pk_get_fingerprint (pk, buf); pk->keyid[0] = _cdk_buftou32 (buf + 12); pk->keyid[1] = _cdk_buftou32 (buf + 16); } } lowbits = pk ? pk->keyid[1] : 0; if (keyid && pk) { keyid[0] = pk->keyid[0]; keyid[1] = pk->keyid[1]; } return lowbits; }
/** * cdk_pk_fingerprint_get_keyid: * @fpr: the key fingerprint * @fprlen: the length of the fingerprint * * Derive the key ID from the key fingerprint. * For version 3 keys, this is not working. **/ u32 cdk_pk_fingerprint_get_keyid(const byte * fpr, size_t fprlen, u32 * keyid) { u32 lowbits = 0; /* In this case we say the key is a V3 RSA key and we can't use the fingerprint to get the keyid. */ if (fpr && fprlen == 16) { keyid[0] = 0; keyid[1] = 0; return 0; } else if (keyid && fpr) { keyid[0] = _cdk_buftou32(fpr + 12); keyid[1] = _cdk_buftou32(fpr + 16); lowbits = keyid[1]; } else if (fpr) lowbits = _cdk_buftou32(fpr + 16); return lowbits; }
/** * cdk_pk_get_keyid: * @pk: the public key * @keyid: buffer to store the key ID * * Calculate the key ID of the given public key. **/ u32 cdk_pk_get_keyid(cdk_pubkey_t pk, u32 * keyid) { u32 lowbits = 0; byte buf[24]; int rc; if (pk && (!pk->keyid[0] || !pk->keyid[1])) { if (pk->version < 4 && is_RSA(pk->pubkey_algo)) { byte p[MAX_MPI_BYTES]; size_t n; n = MAX_MPI_BYTES; rc = _gnutls_mpi_print(pk->mpi[0], p, &n); if (rc < 0 || n < 8) { keyid[0] = keyid[1] = (u32)-1; return (u32)-1; } pk->keyid[0] = p[n - 8] << 24 | p[n - 7] << 16 | p[n - 6] << 8 | p[n - 5]; pk->keyid[1] = p[n - 4] << 24 | p[n - 3] << 16 | p[n - 2] << 8 | p[n - 1]; } else if (pk->version == 4) { cdk_pk_get_fingerprint(pk, buf); pk->keyid[0] = _cdk_buftou32(buf + 12); pk->keyid[1] = _cdk_buftou32(buf + 16); } } lowbits = pk ? pk->keyid[1] : 0; if (keyid && pk) { keyid[0] = pk->keyid[0]; keyid[1] = pk->keyid[1]; } return lowbits; }
static cdk_error_t parse_sig_subpackets (cdk_pkt_signature_t sig) { cdk_subpkt_t node; /* Setup the standard packet entries, so we can use V4 signatures similar to V3. */ for (node = sig->unhashed; node; node = node->next) { if (node->type == CDK_SIGSUBPKT_ISSUER && node->size >= 8) { sig->keyid[0] = _cdk_buftou32 (node->d); sig->keyid[1] = _cdk_buftou32 (node->d + 4); } else if (node->type == CDK_SIGSUBPKT_EXPORTABLE && node->d[0] == 0) { /* Sometimes this packet might be placed in the unhashed area */ sig->flags.exportable = 0; } } for (node = sig->hashed; node; node = node->next) { if (node->type == CDK_SIGSUBPKT_SIG_CREATED && node->size >= 4) sig->timestamp = _cdk_buftou32 (node->d); else if (node->type == CDK_SIGSUBPKT_SIG_EXPIRE && node->size >= 4) { sig->expiredate = _cdk_buftou32 (node->d); if (sig->expiredate > 0 && sig->expiredate < (u32) time (NULL)) sig->flags.expired = 1; } else if (node->type == CDK_SIGSUBPKT_POLICY) sig->flags.policy_url = 1; else if (node->type == CDK_SIGSUBPKT_NOTATION) sig->flags.notation = 1; else if (node->type == CDK_SIGSUBPKT_REVOCABLE && node->d[0] == 0) sig->flags.revocable = 0; else if (node->type == CDK_SIGSUBPKT_EXPORTABLE && node->d[0] == 0) sig->flags.exportable = 0; } if (sig->sig_class == 0x1F) { cdk_desig_revoker_t r, rnode; for (node = sig->hashed; node; node = node->next) { if (node->type == CDK_SIGSUBPKT_REV_KEY) { if (node->size < 22) continue; rnode = cdk_calloc (1, sizeof *rnode); if (!rnode) return CDK_Out_Of_Core; rnode->r_class = node->d[0]; rnode->algid = node->d[1]; memcpy (rnode->fpr, node->d + 2, KEY_FPR_LEN); if (!sig->revkeys) sig->revkeys = rnode; else { for (r = sig->revkeys; r->next; r = r->next) ; r->next = rnode; } } } } return 0; }
static cdk_error_t read_attribute (cdk_stream_t inp, size_t pktlen, cdk_pkt_userid_t attr) { const byte *p; byte *buf; size_t len, nread; cdk_error_t rc; if (!inp || !attr || !pktlen) return CDK_Inv_Value; if (DEBUG_PKT) _cdk_log_debug ("read_attribute: %d octets\n", pktlen); strcpy (attr->name, "[attribute]"); attr->len = strlen (attr->name); buf = cdk_calloc (1, pktlen); if (!buf) return CDK_Out_Of_Core; rc = stream_read (inp, buf, pktlen, &nread); if (rc) { cdk_free (buf); return CDK_Inv_Packet; } p = buf; len = *p++; pktlen--; if (len == 255) { len = _cdk_buftou32 (p); p += 4; pktlen -= 4; } else if (len >= 192) { if (pktlen < 2) { cdk_free (buf); return CDK_Inv_Packet; } len = ((len - 192) << 8) + *p + 192; p++; pktlen--; } if (*p != 1) /* Currently only 1, meaning an image, is defined. */ { cdk_free (buf); return CDK_Inv_Packet; } p++; len--; if (pktlen - (len + 1) > 0) return CDK_Inv_Packet; attr->attrib_img = cdk_calloc (1, len); if (!attr->attrib_img) { cdk_free (buf); return CDK_Out_Of_Core; } attr->attrib_len = len; memcpy (attr->attrib_img, p, len); cdk_free (buf); return rc; }
static int keydb_parse_allsigs( cdk_kbnode_t knode, cdk_keydb_hd_t hd, int check ) { cdk_kbnode_t node, kb; cdk_pkt_signature_t sig; cdk_pkt_pubkey_t pk; struct cdk_subpkt_s * s = NULL; u32 expiredate = 0, curtime = _cdk_timestamp (); u32 keyid[2]; int rc = 0; if( !knode ) return CDK_Inv_Value; if( check && !hd ) return CDK_Inv_Mode; kb = cdk_kbnode_find( knode, CDK_PKT_SECRET_KEY ); if( kb ) return 0; /* reset */ for( node = knode; node; node = node->next ) { if( node->pkt->pkttype == CDK_PKT_USER_ID ) node->pkt->pkt.user_id->is_revoked = 0; else if( node->pkt->pkttype == CDK_PKT_PUBLIC_KEY || node->pkt->pkttype == CDK_PKT_PUBLIC_SUBKEY ) node->pkt->pkt.public_key->is_revoked = 0; } kb = cdk_kbnode_find( knode, CDK_PKT_PUBLIC_KEY ); if( !kb ) return CDK_Inv_Packet; cdk_pk_get_keyid( kb->pkt->pkt.public_key, keyid ); for( node = knode; node; node = node->next) { if( node->pkt->pkttype == CDK_PKT_SIGNATURE ) { sig = node->pkt->pkt.signature; /* Revocation certificates for primary keys */ if( sig->sig_class == 0x20 ) { kb = cdk_kbnode_find_prev( knode, node, CDK_PKT_PUBLIC_KEY ); if( kb ) { kb->pkt->pkt.public_key->is_revoked = 1; if( check ) _cdk_pk_check_sig (hd, kb, node, NULL); } else return CDK_Error_No_Key; } /* Revocation certificates for subkeys */ else if( sig->sig_class == 0x28 ) { kb = cdk_kbnode_find_prev (knode, node, CDK_PKT_PUBLIC_SUBKEY); if( kb ) { kb->pkt->pkt.public_key->is_revoked = 1; if( check ) _cdk_pk_check_sig( hd, kb, node, NULL ); } else return CDK_Error_No_Key; } /* Revocation certifcates for user ID's */ else if( sig->sig_class == 0x30 ) { if( sig->keyid[0] != keyid[0] || sig->keyid[1] != keyid[1] ) continue; /* revokes an earlier signature, no userID. */ kb = cdk_kbnode_find_prev (knode, node, CDK_PKT_USER_ID); if( kb ) { kb->pkt->pkt.user_id->is_revoked = 1; if( check ) _cdk_pk_check_sig( hd, kb, node, NULL ); } else return CDK_Error_No_Key; } /* Direct certificates for primary keys */ else if( sig->sig_class == 0x1F ) { kb = cdk_kbnode_find_prev( knode, node, CDK_PKT_PUBLIC_KEY ); if( kb ) { pk = kb->pkt->pkt.public_key; pk->is_invalid = 0; s = cdk_subpkt_find( node->pkt->pkt.signature->hashed, CDK_SIGSUBPKT_KEY_EXPIRE ); if( s ) { expiredate = _cdk_buftou32( s->d ); pk->expiredate = pk->timestamp + expiredate; pk->has_expired = pk->expiredate > curtime? 0 : 1; } if( check ) _cdk_pk_check_sig( hd, kb, node, NULL ); } else return CDK_Error_No_Key; } /* Direct certificates for subkeys */ else if( sig->sig_class == 0x18 ) { kb = cdk_kbnode_find_prev( knode, node, CDK_PKT_PUBLIC_SUBKEY); if( kb ) { pk = kb->pkt->pkt.public_key; pk->is_invalid = 0; s = cdk_subpkt_find( node->pkt->pkt.signature->hashed, CDK_SIGSUBPKT_KEY_EXPIRE ); if( s ) { expiredate = _cdk_buftou32( s->d ); pk->expiredate = pk->timestamp + expiredate; pk->has_expired = pk->expiredate > curtime? 0 : 1; } if( check ) _cdk_pk_check_sig( hd, kb, node, NULL ); } else return CDK_Error_No_Key; } } } node = cdk_kbnode_find( knode, CDK_PKT_PUBLIC_KEY ); if( node && node->pkt->pkt.public_key->version == 3 ) { /* v3 public keys have no additonal signatures for the key directly. we say the key is valid when we have at least a self signature. */ pk = node->pkt->pkt.public_key; for( node = knode; node; node = node->next ) { if( is_selfsig( node, keyid ) ) { pk->is_invalid = 0; break; } } } if( node && (node->pkt->pkt.public_key->is_revoked || node->pkt->pkt.public_key->has_expired) ) { /* if the primary key has been revoked, mark all subkeys as invalid because without a primary key they are not useable */ for( node = knode; node; node = node->next ) { if( node->pkt->pkttype == CDK_PKT_PUBLIC_SUBKEY ) node->pkt->pkt.public_key->is_invalid = 1; } } return rc; }
static int keydb_merge_selfsig( cdk_kbnode_t key, u32 * keyid ) { cdk_kbnode_t node, kbnode, unode; cdk_subpkt_t s = NULL; cdk_pkt_signature_t sig = NULL; cdk_pkt_userid_t uid = NULL; const byte * symalg = NULL, * hashalg = NULL, * compalg = NULL; size_t nsymalg = 0, nhashalg = 0, ncompalg = 0, n = 0; int key_usage = 0, key_expire = 0; if (!key) return CDK_Inv_Value; for( node = key; node; node = node->next ) { if( !is_selfsig( node, keyid ) ) continue; unode = cdk_kbnode_find_prev( key, node, CDK_PKT_USER_ID ); if( !unode ) return CDK_Error_No_Key; uid = unode->pkt->pkt.user_id; sig = node->pkt->pkt.signature; s = cdk_subpkt_find( sig->hashed, CDK_SIGSUBPKT_PRIMARY_UID ); if( s ) uid->is_primary = 1; s = cdk_subpkt_find( sig->hashed, CDK_SIGSUBPKT_FEATURES ); if( s && s->size == 1 && s->d[0] & 0x01 ) uid->mdc_feature = 1; s = cdk_subpkt_find( sig->hashed, CDK_SIGSUBPKT_KEY_EXPIRE ); if( s && s->size == 4 ) key_expire = _cdk_buftou32( s->d ); s = cdk_subpkt_find( sig->hashed, CDK_SIGSUBPKT_KEY_FLAGS ); if( s ) { if( s->d[0] & 3 ) /* cert + sign data */ key_usage |= PK_USAGE_SIGN; if( s->d[0] & 12 ) /* encrypt comm. + storage */ key_usage |= PK_USAGE_ENCR; } s = cdk_subpkt_find( sig->hashed, CDK_SIGSUBPKT_PREFS_SYM ); if( s ) { symalg = s->d; nsymalg = s->size; n += s->size + 1; } s = cdk_subpkt_find( sig->hashed, CDK_SIGSUBPKT_PREFS_HASH ); if( s ) { hashalg = s->d; nhashalg = s->size; n += s->size + 1; } s = cdk_subpkt_find( sig->hashed, CDK_SIGSUBPKT_PREFS_ZIP ); if( s ) { compalg = s->d; ncompalg = s->size; n += s->size + 1; } if( !n || !hashalg || !compalg || !symalg ) uid->prefs = NULL; else { uid->prefs = cdk_calloc( 1, sizeof (*uid->prefs) * (n + 1) ); if( !uid->prefs ) return CDK_Out_Of_Core; n = 0; for( ; nsymalg; nsymalg--, n++ ) { uid->prefs[n].type = CDK_PREFTYPE_SYM; uid->prefs[n].value = *symalg++; } for( ; nhashalg; nhashalg--, n++ ) { uid->prefs[n].type = CDK_PREFTYPE_HASH; uid->prefs[n].value = *hashalg++; } for( ; ncompalg; ncompalg--, n++ ) { uid->prefs[n].type = CDK_PREFTYPE_ZIP; uid->prefs[n].value = *compalg++; } /* end of list marker */ uid->prefs[n].type = CDK_PREFTYPE_NONE; uid->prefs[n].value = 0; uid->prefs_size = n; kbnode = cdk_kbnode_find_prev( key, node, CDK_PKT_PUBLIC_KEY ); if( kbnode ) { cdk_pkt_pubkey_t pk = kbnode->pkt->pkt.public_key; if( uid->prefs && n ) { pk->prefs = _cdk_copy_prefs( uid->prefs ); pk->prefs_size = n; } if( key_expire ) { pk->expiredate = pk->timestamp + key_expire; pk->has_expired = pk->expiredate> _cdk_timestamp ()?0 :1; } if( key_usage && !pk->pubkey_usage ) pk->pubkey_usage = key_usage; pk->is_invalid = 0; } } } return 0; }