/* final part of the hash */ static uint8_t *hash_finish( gcry_md_hd_t hd, signature_packet_t *p_sig ) { if( p_sig->version == 3 ) { gcry_md_putc( hd, p_sig->type ); gcry_md_write( hd, &p_sig->specific.v3.timestamp, 4 ); } else if( p_sig->version == 4 ) { gcry_md_putc( hd, p_sig->version ); gcry_md_putc( hd, p_sig->type ); gcry_md_putc( hd, p_sig->public_key_algo ); gcry_md_putc( hd, p_sig->digest_algo ); gcry_md_write( hd, p_sig->specific.v4.hashed_data_len, 2 ); size_t i_len = scalar_number( p_sig->specific.v4.hashed_data_len, 2 ); gcry_md_write( hd, p_sig->specific.v4.hashed_data, i_len ); gcry_md_putc( hd, 0x04 ); gcry_md_putc( hd, 0xFF ); i_len += 6; /* hashed data + 6 bytes header */ gcry_md_putc( hd, (i_len >> 24) & 0xff ); gcry_md_putc( hd, (i_len >> 16) & 0xff ); gcry_md_putc( hd, (i_len >> 8) & 0xff ); gcry_md_putc( hd, (i_len) & 0xff ); }
/* final part of the hash */ static int hash_finish(HCRYPTHASH hHash, signature_packet_t *p_sig) { if (p_sig->version == 3) { CryptHashChar(hHash, p_sig->type); CryptHashData(hHash, (unsigned char*)&p_sig->specific.v3.timestamp, 4, 0); } else if (p_sig->version == 4) { CryptHashChar(hHash, p_sig->version); CryptHashChar(hHash, p_sig->type); CryptHashChar(hHash, p_sig->public_key_algo); CryptHashChar(hHash, p_sig->digest_algo); CryptHashData(hHash, p_sig->specific.v4.hashed_data_len, 2, 0); unsigned int i_len = scalar_number(p_sig->specific.v4.hashed_data_len, 2); CryptHashData(hHash, p_sig->specific.v4.hashed_data, i_len, 0); CryptHashChar(hHash, 0x04); CryptHashChar(hHash, 0xFF); i_len += 6; /* hashed data + 6 bytes header */ CryptHashChar(hHash, (i_len >> 24) & 0xff); CryptHashChar(hHash, (i_len >> 16) & 0xff); CryptHashChar(hHash, (i_len >> 8) & 0xff); CryptHashChar(hHash, (i_len) & 0xff); }
static int LoadSignature(const CString &signatureFilename, signature_packet_t *p_sig) { FILE * pFile = _tfsopen(signatureFilename, _T("rb"), SH_DENYWR); if (pFile) { int size = 65536; std::unique_ptr<unsigned char[]> buffer(new unsigned char[size]); int length = 0; if ((length = (int)fread(buffer.get(), sizeof(char), size, pFile)) >= 8) { fclose(pFile); // is unpacking needed? if ((uint8_t)buffer[0] < 0x80) { std::unique_ptr<unsigned char[]> unpacked(new unsigned char[size]); size = pgp_unarmor((char *)buffer.get(), length, unpacked.get(), length); if (size < 2) return -1; buffer.swap(unpacked); } else size = length; if (packet_type(buffer[0]) != SIGNATURE_PACKET) return -1; DWORD i_header_len = packet_header_len(buffer[0]); if ((i_header_len != 1 && i_header_len != 2 && i_header_len != 4) || i_header_len + 1 > (DWORD)size) return -1; DWORD i_len = scalar_number((uint8_t *)(buffer.get() + 1), i_header_len); if (i_len + i_header_len + 1 != (DWORD)size) return -1; if (parse_signature_packet(p_sig, (uint8_t *)(buffer.get() + 1 + i_header_len), i_len)) return -1; if (p_sig->type != BINARY_SIGNATURE && p_sig->type != TEXT_SIGNATURE) { if (p_sig->version == 4) { free(p_sig->specific.v4.hashed_data); free(p_sig->specific.v4.unhashed_data); } return -1; } return 0; } else fclose(pFile); } return -1; }
/* number of data bytes in a MPI */ static int mpi_len(const uint8_t *mpi) { return (scalar_number(mpi, 2) + 7) / 8; }
/* * fill a public_key_t with public key data, including: * * public key packet * * signature packet issued by key which long id is p_sig_issuer * * user id packet */ int parse_public_key( const uint8_t *p_key_data, size_t i_key_len, public_key_t *p_key, const uint8_t *p_sig_issuer ) { const uint8_t *pos = p_key_data; const uint8_t *max_pos = pos + i_key_len; int i_status = 0; #define PUBLIC_KEY_FOUND 0x01 #define USER_ID_FOUND 0x02 #define SIGNATURE_FOUND 0X04 uint8_t *p_key_unarmored = NULL; p_key->psz_username = NULL; p_key->sig.specific.v4.hashed_data = NULL; p_key->sig.specific.v4.unhashed_data = NULL; if( !( *pos & 0x80 ) ) { /* first byte is ASCII, unarmoring */ p_key_unarmored = (uint8_t*)malloc( i_key_len ); if( !p_key_unarmored ) return VLC_ENOMEM; int i_len = pgp_unarmor( (char*)p_key_data, i_key_len, p_key_unarmored, i_key_len ); if( i_len == 0 ) goto error; pos = p_key_unarmored; max_pos = pos + i_len; } while( pos < max_pos ) { if( !(*pos & 0x80) || *pos & 0x40 ) goto error; int i_type = packet_type( *pos ); int i_header_len = packet_header_len( *pos++ ); if( pos + i_header_len > max_pos || ( i_header_len != 1 && i_header_len != 2 && i_header_len != 4 ) ) goto error; int i_packet_len = scalar_number( pos, i_header_len ); pos += i_header_len; if( pos + i_packet_len > max_pos ) goto error; switch( i_type ) { case PUBLIC_KEY_PACKET: i_status |= PUBLIC_KEY_FOUND; if( parse_public_key_packet( &p_key->key, pos, i_packet_len ) != VLC_SUCCESS ) goto error; break; case SIGNATURE_PACKET: /* we accept only v4 signatures here */ if( i_status & SIGNATURE_FOUND || !p_sig_issuer ) break; int i_ret = parse_signature_packet( &p_key->sig, pos, i_packet_len ); if( i_ret == VLC_SUCCESS ) { if( p_key->sig.version != 4 ) break; if( memcmp( p_key->sig.issuer_longid, p_sig_issuer, 8 ) ) { free( p_key->sig.specific.v4.hashed_data ); free( p_key->sig.specific.v4.unhashed_data ); p_key->sig.specific.v4.hashed_data = NULL; p_key->sig.specific.v4.unhashed_data = NULL; break; } i_status |= SIGNATURE_FOUND; } break; case USER_ID_PACKET: if( p_key->psz_username ) /* save only the first User ID */ break; i_status |= USER_ID_FOUND; p_key->psz_username = (uint8_t*)malloc( i_packet_len + 1); if( !p_key->psz_username ) goto error; memcpy( p_key->psz_username, pos, i_packet_len ); p_key->psz_username[i_packet_len] = '\0'; break; default: break; } pos += i_packet_len; } free( p_key_unarmored ); if( !( i_status & ( PUBLIC_KEY_FOUND | USER_ID_FOUND ) ) ) return VLC_EGENERIC; if( p_sig_issuer && !( i_status & SIGNATURE_FOUND ) ) return VLC_EGENERIC; return VLC_SUCCESS; error: if( p_key->sig.version == 4 ) { free( p_key->sig.specific.v4.hashed_data ); free( p_key->sig.specific.v4.unhashed_data ); } free( p_key->psz_username ); free( p_key_unarmored ); return VLC_EGENERIC; }
/* * fill a signature_packet_v4_t from signature packet data * verify that it was used with a DSA or RSA public key */ static size_t parse_signature_v4_packet( signature_packet_t *p_sig, const uint8_t *p_buf, size_t i_sig_len ) { size_t i_read = 1; /* we already read the version byte */ if( i_sig_len < 10 ) /* signature is at least 10 bytes + the 2 MPIs */ return 0; p_sig->type = *p_buf++; i_read++; p_sig->public_key_algo = *p_buf++; i_read++; if (p_sig->public_key_algo != GCRY_PK_DSA && p_sig->public_key_algo != GCRY_PK_RSA ) return 0; p_sig->digest_algo = *p_buf++; i_read++; memcpy( p_sig->specific.v4.hashed_data_len, p_buf, 2 ); p_buf += 2; i_read += 2; size_t i_hashed_data_len = scalar_number( p_sig->specific.v4.hashed_data_len, 2 ); i_read += i_hashed_data_len; if( i_read + 4 > i_sig_len ) return 0; p_sig->specific.v4.hashed_data = (uint8_t*) malloc( i_hashed_data_len ); if( !p_sig->specific.v4.hashed_data ) return 0; memcpy( p_sig->specific.v4.hashed_data, p_buf, i_hashed_data_len ); p_buf += i_hashed_data_len; memcpy( p_sig->specific.v4.unhashed_data_len, p_buf, 2 ); p_buf += 2; i_read += 2; size_t i_unhashed_data_len = scalar_number( p_sig->specific.v4.unhashed_data_len, 2 ); i_read += i_unhashed_data_len; if( i_read + 2 > i_sig_len ) return 0; p_sig->specific.v4.unhashed_data = (uint8_t*) malloc( i_unhashed_data_len ); if( !p_sig->specific.v4.unhashed_data ) return 0; memcpy( p_sig->specific.v4.unhashed_data, p_buf, i_unhashed_data_len ); p_buf += i_unhashed_data_len; memcpy( p_sig->hash_verification, p_buf, 2 ); p_buf += 2; i_read += 2; uint8_t *p, *max_pos; p = p_sig->specific.v4.unhashed_data; max_pos = p + scalar_number( p_sig->specific.v4.unhashed_data_len, 2 ); for( ;; ) { if( p > max_pos ) return 0; size_t i_subpacket_len; if( *p < 192 ) { if( p + 1 > max_pos ) return 0; i_subpacket_len = *p++; } else if( *p < 255 ) { if( p + 2 > max_pos ) return 0; i_subpacket_len = (*p++ - 192) << 8; i_subpacket_len += *p++ + 192; } else { if( ++p + 4 > max_pos ) return 0; i_subpacket_len = U32_AT(p); p += 4; } if( *p == ISSUER_SUBPACKET ) { if( p + 9 > max_pos ) return 0; memcpy( &p_sig->issuer_longid, p+1, 8 ); return i_read; } p += i_subpacket_len; } }