/** * cdk_pk_get_fingerprint: * @pk: the public key * @fpr: the buffer to hold the fingerprint * * Return the fingerprint of the given public key. * The buffer must be at least 20 octets. * This function should be considered deprecated and * the new cdk_pk_to_fingerprint() should be used whenever * possible to avoid overflows. **/ cdk_error_t cdk_pk_get_fingerprint(cdk_pubkey_t pk, byte * fpr) { digest_hd_st hd; int md_algo; int dlen = 0; int err; const mac_entry_st *me; if (!pk || !fpr) return CDK_Inv_Value; if (pk->version < 4 && is_RSA(pk->pubkey_algo)) md_algo = GNUTLS_DIG_MD5; /* special */ else md_algo = GNUTLS_DIG_SHA1; me = mac_to_entry(md_algo); dlen = _gnutls_hash_get_algo_len(me); err = _gnutls_hash_init(&hd, me); if (err < 0) { gnutls_assert(); return map_gnutls_error(err); } _cdk_hash_pubkey(pk, &hd, 1); _gnutls_hash_deinit(&hd, fpr); if (dlen == 16) memset(fpr + 16, 0, 4); return 0; }
/* generate x = SHA(s | SHA(U | ":" | p)) * The output is exactly 20 bytes */ static int _gnutls_calc_srp_sha(const char *username, const char *password, uint8_t * salt, int salt_size, size_t * size, void *digest) { digest_hd_st td; uint8_t res[MAX_HASH_SIZE]; int ret; const mac_entry_st *me = mac_to_entry(GNUTLS_MAC_SHA1); *size = 20; ret = _gnutls_hash_init(&td, me); if (ret < 0) { return GNUTLS_E_MEMORY_ERROR; } _gnutls_hash(&td, username, strlen(username)); _gnutls_hash(&td, ":", 1); _gnutls_hash(&td, password, strlen(password)); _gnutls_hash_deinit(&td, res); ret = _gnutls_hash_init(&td, me); if (ret < 0) { return GNUTLS_E_MEMORY_ERROR; } _gnutls_hash(&td, salt, salt_size); _gnutls_hash(&td, res, 20); /* 20 bytes is the output of sha1 */ _gnutls_hash_deinit(&td, digest); return 0; }
static int digest_ticket(const gnutls_datum_t * key, struct ticket_st *ticket, uint8_t * digest) { mac_hd_st digest_hd; uint16_t length16; int ret; ret = _gnutls_mac_init(&digest_hd, mac_to_entry(TICKET_MAC_ALGO), key->data, key->size); if (ret < 0) { gnutls_assert(); return ret; } _gnutls_mac(&digest_hd, ticket->key_name, TICKET_KEY_NAME_SIZE); _gnutls_mac(&digest_hd, ticket->IV, TICKET_IV_SIZE); length16 = _gnutls_conv_uint16(ticket->encrypted_state_len); _gnutls_mac(&digest_hd, &length16, 2); _gnutls_mac(&digest_hd, ticket->encrypted_state, ticket->encrypted_state_len); _gnutls_mac_deinit(&digest_hd, digest); return 0; }
static int ssl3_sha(int i, uint8_t * secret, int secret_len, uint8_t * rnd, int rnd_len, void *digest) { int j, ret; uint8_t text1[26]; digest_hd_st td; for (j = 0; j < i + 1; j++) { text1[j] = 65 + i; /* A==65 */ } ret = _gnutls_hash_init(&td, mac_to_entry(GNUTLS_MAC_SHA1)); if (ret < 0) { gnutls_assert(); return ret; } _gnutls_hash(&td, text1, i + 1); _gnutls_hash(&td, secret, secret_len); _gnutls_hash(&td, rnd, rnd_len); _gnutls_hash_deinit(&td, digest); return 0; }
static int ssl3_md5(int i, uint8_t * secret, int secret_len, uint8_t * rnd, int rnd_len, void *digest) { uint8_t tmp[MAX_HASH_SIZE]; digest_hd_st td; int ret; ret = _gnutls_hash_init(&td, mac_to_entry(GNUTLS_MAC_MD5)); if (ret < 0) { gnutls_assert(); return ret; } _gnutls_hash(&td, secret, secret_len); ret = ssl3_sha(i, secret, secret_len, rnd, rnd_len, tmp); if (ret < 0) { gnutls_assert(); _gnutls_hash_deinit(&td, digest); return ret; } _gnutls_hash(&td, tmp, SHA1_DIGEST_OUTPUT); _gnutls_hash_deinit(&td, digest); return 0; }
int _gnutls_ssl3_hash_md5(const void *first, int first_len, const void *second, int second_len, int ret_len, uint8_t * ret) { uint8_t digest[MAX_HASH_SIZE]; digest_hd_st td; int block = MD5_DIGEST_OUTPUT; int rc; rc = _gnutls_hash_init(&td, mac_to_entry(GNUTLS_MAC_MD5)); if (rc < 0) { gnutls_assert(); return rc; } _gnutls_hash(&td, first, first_len); _gnutls_hash(&td, second, second_len); _gnutls_hash_deinit(&td, digest); if (ret_len > block) { gnutls_assert(); return GNUTLS_E_INTERNAL_ERROR; } memcpy(ret, digest, ret_len); return 0; }
/* Randomizes the given password entry. It actually sets the verifier * to random data and sets the salt based on fake_salt_seed and * username. Returns 0 on success. */ static int _randomize_pwd_entry(SRP_PWD_ENTRY * entry, gnutls_srp_server_credentials_t sc, const char * username) { int ret; const mac_entry_st *me = mac_to_entry(SRP_FAKE_SALT_MAC); mac_hd_st ctx; size_t username_len = strlen(username); if (entry->g.size == 0 || entry->n.size == 0) { gnutls_assert(); return GNUTLS_E_INTERNAL_ERROR; } entry->v.data = gnutls_malloc(20); entry->v.size = 20; if (entry->v.data == NULL) { gnutls_assert(); return GNUTLS_E_MEMORY_ERROR; } ret = _gnutls_rnd(GNUTLS_RND_RANDOM, entry->v.data, 20); if (ret < 0) { gnutls_assert(); return ret; } /* Always allocate and work with the output size of the MAC, * even if they don't need salts that long, for convenience. * * In case an error occurs 'entry' (and the salt inside) * is deallocated by our caller: _gnutls_srp_pwd_read_entry(). */ entry->salt.data = gnutls_malloc(me->output_size); if (entry->salt.data == NULL) { gnutls_assert(); return GNUTLS_E_MEMORY_ERROR; } ret = _gnutls_mac_init(&ctx, me, sc->fake_salt_seed.data, sc->fake_salt_seed.size); if (ret < 0) { gnutls_assert(); return ret; } _gnutls_mac(&ctx, "salt", 4); _gnutls_mac(&ctx, username, username_len); _gnutls_mac_deinit(&ctx, entry->salt.data); /* Set length to the actual number of bytes they asked for. * This is always less than or equal to the output size of * the MAC, enforced by gnutls_srp_set_server_fake_salt_seed(). */ entry->salt.size = sc->fake_salt_length; return 0; }
const mac_entry_st *_gnutls_cipher_suite_get_mac_algo(const uint8_t suite[2]) { /* In bytes */ int ret = 0; CIPHER_SUITE_ALG_LOOP(ret = p->mac_algorithm); return mac_to_entry(ret); }
/** * gnutls_sign_is_secure: * @algorithm: is a sign algorithm * * Returns: Non-zero if the provided signature algorithm is considered to be secure. **/ int gnutls_sign_is_secure (gnutls_sign_algorithm_t algorithm) { gnutls_sign_algorithm_t sign = algorithm; gnutls_digest_algorithm_t dig = GNUTLS_DIG_UNKNOWN; /* avoid prefix */ GNUTLS_SIGN_ALG_LOOP (dig = p->mac); if (dig != GNUTLS_DIG_UNKNOWN) return _gnutls_digest_is_secure(mac_to_entry(dig)); return 0; }
static int openssl_hash_password(const char *pass, gnutls_datum_t * key, gnutls_datum_t * salt) { unsigned char md5[16]; digest_hd_st hd; unsigned int count = 0; int err; while (count < key->size) { err = _gnutls_hash_init(&hd, mac_to_entry(GNUTLS_MAC_MD5)); if (err) { gnutls_assert(); return err; } if (count) { err = _gnutls_hash(&hd, md5, sizeof(md5)); if (err) { hash_err: _gnutls_hash_deinit(&hd, NULL); gnutls_assert(); return err; } } if (pass) { err = _gnutls_hash(&hd, pass, strlen(pass)); if (err) { gnutls_assert(); goto hash_err; } } err = _gnutls_hash(&hd, salt->data, 8); if (err) { gnutls_assert(); goto hash_err; } _gnutls_hash_deinit(&hd, md5); if (key->size - count <= sizeof(md5)) { memcpy(&key->data[count], md5, key->size - count); break; } memcpy(&key->data[count], md5, sizeof(md5)); count += sizeof(md5); } return 0; }
/** * gnutls_srp_set_server_fake_salt_seed: * @cred: is a #gnutls_srp_server_credentials_t type * @seed: is the seed data, only needs to be valid until the function * returns; size of the seed must be greater than zero * @salt_length: is the length of the generated fake salts * * This function sets the seed that is used to generate salts for * invalid (non-existent) usernames. * * In order to prevent attackers from guessing valid usernames, * when a user does not exist gnutls generates a salt and a verifier * and proceeds with the protocol as usual. * The authentication will ultimately fail, but the client cannot tell * whether the username is valid (exists) or invalid. * * If an attacker learns the seed, given a salt (which is part of the * handshake) which was generated when the seed was in use, it can tell * whether or not the authentication failed because of an unknown username. * This seed cannot be used to reveal application data or passwords. * * @salt_length should represent the salt length your application uses. * Generating fake salts longer than 20 bytes is not supported. * * By default the seed is a random value, different each time a * #gnutls_srp_server_credentials_t is allocated and fake salts are * 16 bytes long. * * Since: 3.3.0 **/ void gnutls_srp_set_server_fake_salt_seed(gnutls_srp_server_credentials_t cred, const gnutls_datum_t * seed, unsigned int salt_length) { _gnutls_free_datum(&cred->fake_salt_seed); _gnutls_set_datum(&cred->fake_salt_seed, seed->data, seed->size); /* Cap the salt length at the output size of the MAC algorithm * we are using to generate the fake salts. */ const mac_entry_st * me = mac_to_entry(SRP_FAKE_SALT_MAC); const size_t mac_len = me->output_size; cred->fake_salt_length = (salt_length < mac_len ? salt_length : mac_len); }
void _gnutls_epoch_set_null_algos(gnutls_session_t session, record_parameters_st * params) { /* This is only called on startup. We are extra paranoid about this because it may cause unencrypted application data to go out on the wire. */ if (params->initialized || params->epoch != 0) { gnutls_assert(); return; } params->cipher = cipher_to_entry(GNUTLS_CIPHER_NULL); params->mac = mac_to_entry(GNUTLS_MAC_NULL); params->compression_algorithm = GNUTLS_COMP_NULL; params->initialized = 1; }
/** * gnutls_privkey_sign_hash: * @signer: Holds the signer's key * @hash_algo: The hash algorithm used * @flags: Zero or one of %gnutls_privkey_flags_t * @hash_data: holds the data to be signed * @signature: will contain newly allocated signature * * This function will sign the given hashed data using a signature algorithm * supported by the private key. Signature algorithms are always used * together with a hash functions. Different hash functions may be * used for the RSA algorithm, but only SHA-XXX for the DSA keys. * * You may use gnutls_pubkey_get_preferred_hash_algorithm() to determine * the hash algorithm. * * Note that if %GNUTLS_PRIVKEY_SIGN_FLAG_TLS1_RSA flag is specified this function * will ignore @hash_algo and perform a raw PKCS1 signature. * * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a * negative error value. * * Since: 2.12.0 **/ int gnutls_privkey_sign_hash(gnutls_privkey_t signer, gnutls_digest_algorithm_t hash_algo, unsigned int flags, const gnutls_datum_t * hash_data, gnutls_datum_t * signature) { int ret; gnutls_datum_t digest; if (flags & GNUTLS_PRIVKEY_SIGN_FLAG_TLS1_RSA) return gnutls_privkey_sign_raw_data(signer, flags, hash_data, signature); digest.data = gnutls_malloc(hash_data->size); if (digest.data == NULL) { gnutls_assert(); return GNUTLS_E_MEMORY_ERROR; } digest.size = hash_data->size; memcpy(digest.data, hash_data->data, digest.size); ret = pk_prepare_hash(signer->pk_algorithm, mac_to_entry(hash_algo), &digest); if (ret < 0) { gnutls_assert(); goto cleanup; } ret = gnutls_privkey_sign_raw_data(signer, flags, &digest, signature); if (ret < 0) { gnutls_assert(); goto cleanup; } ret = 0; cleanup: _gnutls_free_datum(&digest); return ret; }
/** * gnutls_privkey_sign_data: * @signer: Holds the key * @hash: should be a digest algorithm * @flags: Zero or one of %gnutls_privkey_flags_t * @data: holds the data to be signed * @signature: will contain the signature allocate with gnutls_malloc() * * This function will sign the given data using a signature algorithm * supported by the private key. Signature algorithms are always used * together with a hash functions. Different hash functions may be * used for the RSA algorithm, but only the SHA family for the DSA keys. * * You may use gnutls_pubkey_get_preferred_hash_algorithm() to determine * the hash algorithm. * * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a * negative error value. * * Since: 2.12.0 **/ int gnutls_privkey_sign_data(gnutls_privkey_t signer, gnutls_digest_algorithm_t hash, unsigned int flags, const gnutls_datum_t * data, gnutls_datum_t * signature) { int ret; gnutls_datum_t digest; const mac_entry_st *me = mac_to_entry(hash); if (flags & GNUTLS_PRIVKEY_SIGN_FLAG_TLS1_RSA) return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST); ret = pk_hash_data(signer->pk_algorithm, me, NULL, data, &digest); if (ret < 0) { gnutls_assert(); return ret; } ret = pk_prepare_hash(signer->pk_algorithm, me, &digest); if (ret < 0) { gnutls_assert(); goto cleanup; } ret = gnutls_privkey_sign_raw_data(signer, flags, &digest, signature); _gnutls_free_datum(&digest); if (ret < 0) { gnutls_assert(); return ret; } return 0; cleanup: _gnutls_free_datum(&digest); return ret; }
int _gnutls_epoch_set_cipher_suite(gnutls_session_t session, int epoch_rel, const uint8_t suite[2]) { const cipher_entry_st *cipher_algo; const mac_entry_st *mac_algo; record_parameters_st *params; const gnutls_cipher_suite_entry_st *cs; int ret; ret = _gnutls_epoch_get(session, epoch_rel, ¶ms); if (ret < 0) return gnutls_assert_val(ret); if (params->initialized || params->cipher != NULL || params->mac != NULL) return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR); cs = ciphersuite_to_entry(suite); if (cs == NULL) return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR); cipher_algo = cipher_to_entry(cs->block_algorithm); mac_algo = mac_to_entry(cs->mac_algorithm); if (_gnutls_cipher_is_ok(cipher_algo) == 0 || _gnutls_mac_is_ok(mac_algo) == 0) return gnutls_assert_val(GNUTLS_E_UNWANTED_ALGORITHM); if (_gnutls_cipher_priority(session, cipher_algo->id) < 0) return gnutls_assert_val(GNUTLS_E_UNWANTED_ALGORITHM); if (_gnutls_mac_priority(session, mac_algo->id) < 0) return gnutls_assert_val(GNUTLS_E_UNWANTED_ALGORITHM); params->cipher = cipher_algo; params->mac = mac_algo; return 0; }
/* * Verifies the given certificate against a certificate list of * trusted CAs. * * Returns only 0 or 1. If 1 it means that the certificate * was successfuly verified. * * 'flags': an OR of the gnutls_certificate_verify_flags enumeration. * * Output will hold some extra information about the verification * procedure. */ static unsigned verify_crt(gnutls_x509_crt_t cert, const gnutls_x509_crt_t * trusted_cas, int tcas_size, unsigned int flags, unsigned int *output, verify_state_st *vparams, unsigned end_cert) { gnutls_datum_t cert_signed_data = { NULL, 0 }; gnutls_datum_t cert_signature = { NULL, 0 }; gnutls_x509_crt_t issuer = NULL; int issuer_version, hash_algo; unsigned result = 1; const mac_entry_st * me; unsigned int out = 0, usage; int sigalg, ret; if (output) *output = 0; if (vparams->max_path == 0) { MARK_INVALID(GNUTLS_CERT_SIGNER_CONSTRAINTS_FAILURE); /* bail immediately, to avoid inconistency */ goto cleanup; } vparams->max_path--; if (tcas_size >= 1) issuer = find_issuer(cert, trusted_cas, tcas_size); ret = _gnutls_x509_get_signed_data(cert->cert, &cert->der, "tbsCertificate", &cert_signed_data); if (ret < 0) { MARK_INVALID(0); cert_signed_data.data = NULL; } ret = _gnutls_x509_get_signature(cert->cert, "signature", &cert_signature); if (ret < 0) { MARK_INVALID(0); cert_signature.data = NULL; } ret = _gnutls_x509_get_signature_algorithm(cert->cert, "signatureAlgorithm.algorithm"); if (ret < 0) { MARK_INVALID(0); } sigalg = ret; /* issuer is not in trusted certificate * authorities. */ if (issuer == NULL) { MARK_INVALID(GNUTLS_CERT_SIGNER_NOT_FOUND); } else { if (vparams->nc != NULL) { /* append the issuer's constraints */ ret = gnutls_x509_crt_get_name_constraints(issuer, vparams->nc, GNUTLS_NAME_CONSTRAINTS_FLAG_APPEND, NULL); if (ret < 0 && ret != GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) { MARK_INVALID(GNUTLS_CERT_SIGNER_CONSTRAINTS_FAILURE); goto nc_done; } /* only check name constraints in server certificates, not CAs */ if (end_cert != 0) { ret = gnutls_x509_name_constraints_check_crt(vparams->nc, GNUTLS_SAN_DNSNAME, cert); if (ret == 0) { MARK_INVALID(GNUTLS_CERT_SIGNER_CONSTRAINTS_FAILURE); goto nc_done; } ret = gnutls_x509_name_constraints_check_crt(vparams->nc, GNUTLS_SAN_RFC822NAME, cert); if (ret == 0) { MARK_INVALID(GNUTLS_CERT_SIGNER_CONSTRAINTS_FAILURE); goto nc_done; } ret = gnutls_x509_name_constraints_check_crt(vparams->nc, GNUTLS_SAN_DN, cert); if (ret == 0) { MARK_INVALID(GNUTLS_CERT_SIGNER_CONSTRAINTS_FAILURE); goto nc_done; } ret = gnutls_x509_name_constraints_check_crt(vparams->nc, GNUTLS_SAN_URI, cert); if (ret == 0) { MARK_INVALID(GNUTLS_CERT_SIGNER_CONSTRAINTS_FAILURE); goto nc_done; } ret = gnutls_x509_name_constraints_check_crt(vparams->nc, GNUTLS_SAN_IPADDRESS, cert); if (ret == 0) { MARK_INVALID(GNUTLS_CERT_SIGNER_CONSTRAINTS_FAILURE); goto nc_done; } } } nc_done: if (vparams->tls_feat != NULL) { /* append the issuer's constraints */ ret = gnutls_x509_crt_get_tlsfeatures(issuer, vparams->tls_feat, GNUTLS_EXT_FLAG_APPEND, NULL); if (ret < 0 && ret != GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) { MARK_INVALID(GNUTLS_CERT_SIGNER_CONSTRAINTS_FAILURE); goto feat_done; } ret = gnutls_x509_tlsfeatures_check_crt(vparams->tls_feat, cert); if (ret == 0) { MARK_INVALID(GNUTLS_CERT_SIGNER_CONSTRAINTS_FAILURE); goto feat_done; } } feat_done: issuer_version = gnutls_x509_crt_get_version(issuer); if (issuer_version < 0) { MARK_INVALID(0); } else if (!(flags & GNUTLS_VERIFY_DISABLE_CA_SIGN) && ((flags & GNUTLS_VERIFY_DO_NOT_ALLOW_X509_V1_CA_CRT) || issuer_version != 1)) { if (check_if_ca(cert, issuer, &vparams->max_path, flags) != 1) { MARK_INVALID(GNUTLS_CERT_SIGNER_NOT_CA); } ret = gnutls_x509_crt_get_key_usage(issuer, &usage, NULL); if (ret != GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) { if (ret < 0) { MARK_INVALID(0); } else if (!(usage & GNUTLS_KEY_KEY_CERT_SIGN)) { MARK_INVALID(GNUTLS_CERT_SIGNER_CONSTRAINTS_FAILURE); } } } if (sigalg >= 0) { hash_algo = gnutls_sign_get_hash_algorithm(sigalg); me = mac_to_entry(hash_algo); } else { me = NULL; } if (me == NULL) { MARK_INVALID(0); } else if (cert_signed_data.data != NULL && cert_signature.data != NULL) { ret = _gnutls_x509_verify_data(me, &cert_signed_data, &cert_signature, issuer); if (ret == GNUTLS_E_PK_SIG_VERIFY_FAILED) { MARK_INVALID(GNUTLS_CERT_SIGNATURE_FAILURE); } else if (ret < 0) { MARK_INVALID(0); } } } /* we always check the issuer for unsupported critical extensions */ if (issuer && check_for_unknown_exts(issuer) != 0) { if (!(flags & GNUTLS_VERIFY_IGNORE_UNKNOWN_CRIT_EXTENSIONS)) { MARK_INVALID(GNUTLS_CERT_UNKNOWN_CRIT_EXTENSIONS); } } /* we only check the end-certificate for critical extensions; that * way do not perform this check twice on the certificates when * verifying a large list */ if (end_cert && check_for_unknown_exts(cert) != 0) { if (!(flags & GNUTLS_VERIFY_IGNORE_UNKNOWN_CRIT_EXTENSIONS)) { MARK_INVALID(GNUTLS_CERT_UNKNOWN_CRIT_EXTENSIONS); } } if (sigalg >= 0) { if (is_level_acceptable(cert, issuer, sigalg, flags) == 0) { MARK_INVALID(GNUTLS_CERT_INSECURE_ALGORITHM); } /* If the certificate is not self signed check if the algorithms * used are secure. If the certificate is self signed it doesn't * really matter. */ if (gnutls_sign_is_secure(sigalg) == 0 && _gnutls_is_broken_sig_allowed(sigalg, flags) == 0 && is_issuer(cert, cert) == 0) { MARK_INVALID(GNUTLS_CERT_INSECURE_ALGORITHM); } } /* Check activation/expiration times */ if (!(flags & GNUTLS_VERIFY_DISABLE_TIME_CHECKS)) { /* check the time of the issuer first */ if (issuer != NULL && !(flags & GNUTLS_VERIFY_DISABLE_TRUSTED_TIME_CHECKS)) { out |= check_time_status(issuer, vparams->now); if (out != 0) { gnutls_assert(); result = 0; } } out |= check_time_status(cert, vparams->now); if (out != 0) { gnutls_assert(); result = 0; } } cleanup: if (output) *output |= out; if (vparams->func) { if (result == 0) { out |= GNUTLS_CERT_INVALID; } vparams->func(cert, issuer, NULL, out); } _gnutls_free_datum(&cert_signed_data); _gnutls_free_datum(&cert_signature); return result; }
/** * gnutls_x509_crl_verify: * @crl: is the crl to be verified * @trusted_cas: is a certificate list that is considered to be trusted one * @tcas_size: holds the number of CA certificates in CA_list * @flags: Flags that may be used to change the verification algorithm. Use OR of the gnutls_certificate_verify_flags enumerations. * @verify: will hold the crl verification output. * * This function will try to verify the given crl and return its verification status. * See gnutls_x509_crt_list_verify() for a detailed description of * return values. Note that since GnuTLS 3.1.4 this function includes * the time checks. * * Note that value in @verify is set only when the return value of this * function is success (i.e, failure to trust a CRL a certificate does not imply * a negative return value). * * Before GnuTLS 3.5.7 this function would return zero or a positive * number on success. * * Returns: On success, %GNUTLS_E_SUCCESS (0), otherwise a * negative error value. **/ int gnutls_x509_crl_verify(gnutls_x509_crl_t crl, const gnutls_x509_crt_t * trusted_cas, unsigned tcas_size, unsigned int flags, unsigned int *verify) { /* CRL is ignored for now */ gnutls_datum_t crl_signed_data = { NULL, 0 }; gnutls_datum_t crl_signature = { NULL, 0 }; gnutls_x509_crt_t issuer = NULL; int result, hash_algo; time_t now = gnutls_time(0); unsigned int usage; if (verify) *verify = 0; if (tcas_size >= 1) issuer = find_crl_issuer(crl, trusted_cas, tcas_size); result = _gnutls_x509_get_signed_data(crl->crl, &crl->der, "tbsCertList", &crl_signed_data); if (result < 0) { gnutls_assert(); if (verify) *verify |= GNUTLS_CERT_INVALID; goto cleanup; } result = _gnutls_x509_get_signature(crl->crl, "signature", &crl_signature); if (result < 0) { gnutls_assert(); if (verify) *verify |= GNUTLS_CERT_INVALID; goto cleanup; } result = _gnutls_x509_get_signature_algorithm(crl->crl, "signatureAlgorithm.algorithm"); if (result < 0) { gnutls_assert(); if (verify) *verify |= GNUTLS_CERT_INVALID; goto cleanup; } hash_algo = gnutls_sign_get_hash_algorithm(result); /* issuer is not in trusted certificate * authorities. */ if (issuer == NULL) { gnutls_assert(); if (verify) *verify |= GNUTLS_CERT_SIGNER_NOT_FOUND | GNUTLS_CERT_INVALID; } else { if (!(flags & GNUTLS_VERIFY_DISABLE_CA_SIGN)) { if (gnutls_x509_crt_get_ca_status(issuer, NULL) != 1) { gnutls_assert(); if (verify) *verify |= GNUTLS_CERT_SIGNER_NOT_CA | GNUTLS_CERT_INVALID; } result = gnutls_x509_crt_get_key_usage(issuer, &usage, NULL); if (result != GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) { if (result < 0) { gnutls_assert(); if (verify) *verify |= GNUTLS_CERT_INVALID; } else if (!(usage & GNUTLS_KEY_CRL_SIGN)) { gnutls_assert(); if (verify) *verify |= GNUTLS_CERT_SIGNER_CONSTRAINTS_FAILURE | GNUTLS_CERT_INVALID; } } } result = _gnutls_x509_verify_data(mac_to_entry(hash_algo), &crl_signed_data, &crl_signature, issuer); if (result == GNUTLS_E_PK_SIG_VERIFY_FAILED) { gnutls_assert(); /* error. ignore it */ if (verify) *verify |= GNUTLS_CERT_SIGNATURE_FAILURE; result = 0; } else if (result < 0) { gnutls_assert(); if (verify) *verify |= GNUTLS_CERT_INVALID; goto cleanup; } else if (result >= 0) { result = 0; /* everything ok */ } } { int sigalg; sigalg = gnutls_x509_crl_get_signature_algorithm(crl); if (((sigalg == GNUTLS_SIGN_RSA_MD2) && !(flags & GNUTLS_VERIFY_ALLOW_SIGN_RSA_MD2)) || ((sigalg == GNUTLS_SIGN_RSA_MD5) && !(flags & GNUTLS_VERIFY_ALLOW_SIGN_RSA_MD5))) { if (verify) *verify |= GNUTLS_CERT_INSECURE_ALGORITHM; result = 0; } } if (gnutls_x509_crl_get_this_update(crl) > now && verify) *verify |= GNUTLS_CERT_REVOCATION_DATA_ISSUED_IN_FUTURE; if (gnutls_x509_crl_get_next_update(crl) < now && verify) *verify |= GNUTLS_CERT_REVOCATION_DATA_SUPERSEDED; cleanup: if (verify && *verify != 0) *verify |= GNUTLS_CERT_INVALID; _gnutls_free_datum(&crl_signed_data); _gnutls_free_datum(&crl_signature); return result; }
/** * gnutls_pkcs12_generate_mac2: * @pkcs12: A pkcs12 type * @mac: the MAC algorithm to use * @pass: The password for the MAC * * This function will generate a MAC for the PKCS12 structure. * * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a * negative error value. **/ int gnutls_pkcs12_generate_mac2(gnutls_pkcs12_t pkcs12, gnutls_mac_algorithm_t mac, const char *pass) { uint8_t salt[8], key[MAX_HASH_SIZE]; int result; const int iter = 10*1024; mac_hd_st td1; gnutls_datum_t tmp = { NULL, 0 }; unsigned mac_size, key_len; uint8_t mac_out[MAX_HASH_SIZE]; const mac_entry_st *me = mac_to_entry(mac); if (pkcs12 == NULL || me == NULL) return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST); if (me->oid == NULL) return gnutls_assert_val(GNUTLS_E_UNIMPLEMENTED_FEATURE); mac_size = _gnutls_mac_get_algo_len(me); key_len = mac_size; /* Generate the salt. */ result = gnutls_rnd(GNUTLS_RND_NONCE, salt, sizeof(salt)); if (result < 0) { gnutls_assert(); return result; } /* Write the salt into the structure. */ result = asn1_write_value(pkcs12->pkcs12, "macData.macSalt", salt, sizeof(salt)); if (result != ASN1_SUCCESS) { gnutls_assert(); result = _gnutls_asn2err(result); goto cleanup; } /* write the iterations */ if (iter > 1) { result = _gnutls_x509_write_uint32(pkcs12->pkcs12, "macData.iterations", iter); if (result < 0) { gnutls_assert(); goto cleanup; } } /* Generate the key. */ #if ENABLE_GOST if (me->id == GNUTLS_MAC_GOSTR_94 || me->id == GNUTLS_MAC_STREEBOG_256 || me->id == GNUTLS_MAC_STREEBOG_512) { key_len = 32; result = _gnutls_pkcs12_gost_string_to_key(me->id, salt, sizeof(salt), iter, pass, mac_size, key); } else #endif result = _gnutls_pkcs12_string_to_key(me, 3 /*MAC*/, salt, sizeof(salt), iter, pass, mac_size, key); if (result < 0) { gnutls_assert(); goto cleanup; } /* Get the data to be MACed */ result = _decode_pkcs12_auth_safe(pkcs12->pkcs12, NULL, &tmp); if (result < 0) { gnutls_assert(); goto cleanup; } /* MAC the data */ result = _gnutls_mac_init(&td1, me, key, key_len); if (result < 0) { gnutls_assert(); goto cleanup; } _gnutls_mac(&td1, tmp.data, tmp.size); _gnutls_free_datum(&tmp); _gnutls_mac_deinit(&td1, mac_out); result = asn1_write_value(pkcs12->pkcs12, "macData.mac.digest", mac_out, mac_size); if (result != ASN1_SUCCESS) { gnutls_assert(); result = _gnutls_asn2err(result); goto cleanup; } result = asn1_write_value(pkcs12->pkcs12, "macData.mac.digestAlgorithm.parameters", NULL, 0); if (result != ASN1_SUCCESS && result != ASN1_ELEMENT_NOT_FOUND) { gnutls_assert(); result = _gnutls_asn2err(result); goto cleanup; } result = asn1_write_value(pkcs12->pkcs12, "macData.mac.digestAlgorithm.algorithm", me->oid, 1); if (result != ASN1_SUCCESS) { gnutls_assert(); result = _gnutls_asn2err(result); goto cleanup; } return 0; cleanup: _gnutls_free_datum(&tmp); return result; }
/** * gnutls_pkcs12_mac_info: * @pkcs12: A pkcs12 type * @mac: the MAC algorithm used as %gnutls_mac_algorithm_t * @salt: the salt used for string to key (if non-NULL then @salt_size initially holds its size) * @salt_size: string to key salt size * @iter_count: string to key iteration count * @oid: if non-NULL it will contain an allocated null-terminated variable with the OID * * This function will provide information on the MAC algorithm used * in a PKCS #12 structure. If the structure algorithms * are unknown the code %GNUTLS_E_UNKNOWN_HASH_ALGORITHM will be returned, * and only @oid, will be set. That is, @oid will be set on structures * with a MAC whether supported or not. It must be deinitialized using gnutls_free(). * The other variables are only set on supported structures. * * Returns: %GNUTLS_E_INVALID_REQUEST if the provided structure doesn't contain a MAC, * %GNUTLS_E_UNKNOWN_HASH_ALGORITHM if the structure's MAC isn't supported, or * another negative error code in case of a failure. Zero on success. **/ int gnutls_pkcs12_mac_info(gnutls_pkcs12_t pkcs12, unsigned int *mac, void *salt, unsigned int *salt_size, unsigned int *iter_count, char **oid) { int ret; gnutls_datum_t tmp = { NULL, 0 }, dsalt = { NULL, 0}; gnutls_mac_algorithm_t algo; if (oid) *oid = NULL; if (pkcs12 == NULL) { gnutls_assert(); return GNUTLS_E_INVALID_REQUEST; } ret = _gnutls_x509_read_value(pkcs12->pkcs12, "macData.mac.digestAlgorithm.algorithm", &tmp); if (ret < 0) { gnutls_assert(); return GNUTLS_E_INVALID_REQUEST; } if (oid) { *oid = (char*)tmp.data; } algo = gnutls_oid_to_digest((char*)tmp.data); if (algo == GNUTLS_MAC_UNKNOWN || mac_to_entry(algo) == NULL) { gnutls_assert(); return GNUTLS_E_UNKNOWN_HASH_ALGORITHM; } if (oid) { tmp.data = NULL; } if (mac) { *mac = algo; } if (iter_count) { ret = _gnutls_x509_read_uint(pkcs12->pkcs12, "macData.iterations", iter_count); if (ret < 0) { *iter_count = 1; /* the default */ } } if (salt) { /* Read the salt from the structure. */ ret = _gnutls_x509_read_null_value(pkcs12->pkcs12, "macData.macSalt", &dsalt); if (ret < 0) { gnutls_assert(); goto cleanup; } if (*salt_size >= (unsigned)dsalt.size) { *salt_size = dsalt.size; if (dsalt.size > 0) memcpy(salt, dsalt.data, dsalt.size); } else { *salt_size = dsalt.size; ret = gnutls_assert_val(GNUTLS_E_SHORT_MEMORY_BUFFER); goto cleanup; } } ret = 0; cleanup: _gnutls_free_datum(&tmp); _gnutls_free_datum(&dsalt); return ret; }
/** * gnutls_pkcs12_verify_mac: * @pkcs12: should contain a gnutls_pkcs12_t type * @pass: The password for the MAC * * This function will verify the MAC for the PKCS12 structure. * * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a * negative error value. **/ int gnutls_pkcs12_verify_mac(gnutls_pkcs12_t pkcs12, const char *pass) { uint8_t key[MAX_HASH_SIZE]; char oid[MAX_OID_SIZE]; int result; unsigned int iter; int len; mac_hd_st td1; gnutls_datum_t tmp = { NULL, 0 }, salt = { NULL, 0}; uint8_t mac_output[MAX_HASH_SIZE]; uint8_t mac_output_orig[MAX_HASH_SIZE]; gnutls_mac_algorithm_t algo; unsigned mac_len, key_len; const mac_entry_st *entry; #if ENABLE_GOST int gost_retry = 0; #endif if (pkcs12 == NULL) { gnutls_assert(); return GNUTLS_E_INVALID_REQUEST; } /* read the iterations */ result = _gnutls_x509_read_uint(pkcs12->pkcs12, "macData.iterations", &iter); if (result < 0) { iter = 1; /* the default */ } len = sizeof(oid); result = asn1_read_value(pkcs12->pkcs12, "macData.mac.digestAlgorithm.algorithm", oid, &len); if (result != ASN1_SUCCESS) { gnutls_assert(); return _gnutls_asn2err(result); } algo = gnutls_oid_to_digest(oid); if (algo == GNUTLS_MAC_UNKNOWN) { unknown_mac: gnutls_assert(); return GNUTLS_E_UNKNOWN_HASH_ALGORITHM; } entry = mac_to_entry(algo); if (entry == NULL) goto unknown_mac; mac_len = _gnutls_mac_get_algo_len(entry); key_len = mac_len; /* Read the salt from the structure. */ result = _gnutls_x509_read_null_value(pkcs12->pkcs12, "macData.macSalt", &salt); if (result < 0) { gnutls_assert(); goto cleanup; } /* Generate the key. */ result = _gnutls_pkcs12_string_to_key(entry, 3 /*MAC*/, salt.data, salt.size, iter, pass, key_len, key); if (result < 0) { gnutls_assert(); goto cleanup; } /* Get the data to be MACed */ result = _decode_pkcs12_auth_safe(pkcs12->pkcs12, NULL, &tmp); if (result < 0) { gnutls_assert(); goto cleanup; } #if ENABLE_GOST /* GOST PKCS#12 files use either PKCS#12 scheme or proprietary * HMAC-based scheme to generate MAC key. */ pkcs12_try_gost: #endif /* MAC the data */ result = _gnutls_mac_init(&td1, entry, key, key_len); if (result < 0) { gnutls_assert(); goto cleanup; } _gnutls_mac(&td1, tmp.data, tmp.size); _gnutls_mac_deinit(&td1, mac_output); len = sizeof(mac_output_orig); result = asn1_read_value(pkcs12->pkcs12, "macData.mac.digest", mac_output_orig, &len); if (result != ASN1_SUCCESS) { gnutls_assert(); result = _gnutls_asn2err(result); goto cleanup; } if ((unsigned)len != mac_len || memcmp(mac_output_orig, mac_output, len) != 0) { #if ENABLE_GOST /* It is possible that GOST files use proprietary * key generation scheme */ if (!gost_retry && (algo == GNUTLS_MAC_GOSTR_94 || algo == GNUTLS_MAC_STREEBOG_256 || algo == GNUTLS_MAC_STREEBOG_512)) { gost_retry = 1; key_len = 32; result = _gnutls_pkcs12_gost_string_to_key(algo, salt.data, salt.size, iter, pass, key_len, key); if (result < 0) { gnutls_assert(); goto cleanup; } goto pkcs12_try_gost; } #endif gnutls_assert(); result = GNUTLS_E_MAC_VERIFY_FAILED; goto cleanup; } result = 0; cleanup: _gnutls_free_datum(&tmp); _gnutls_free_datum(&salt); return result; }
/** * cdk_pk_verify: * @pk: the public key * @sig: signature * @md: the message digest * * Verify the signature in @sig and compare it with the message digest in @md. **/ cdk_error_t cdk_pk_verify(cdk_pubkey_t pk, cdk_pkt_signature_t sig, const byte * md) { gnutls_datum_t s_sig = { NULL, 0 }, di = { NULL, 0}; byte *encmd = NULL; cdk_error_t rc; int ret, algo; unsigned int i; gnutls_pk_params_st params; const mac_entry_st *me; if (!pk || !sig || !md) { gnutls_assert(); return CDK_Inv_Value; } if (is_DSA(pk->pubkey_algo)) algo = GNUTLS_PK_DSA; else if (is_RSA(pk->pubkey_algo)) algo = GNUTLS_PK_RSA; else { gnutls_assert(); return CDK_Inv_Value; } rc = sig_to_datum(&s_sig, sig); if (rc) { gnutls_assert(); goto leave; } me = mac_to_entry(sig->digest_algo); rc = _gnutls_set_datum(&di, md, _gnutls_hash_get_algo_len(me)); if (rc < 0) { rc = gnutls_assert_val(CDK_Out_Of_Core); goto leave; } rc = pk_prepare_hash(algo, me, &di); if (rc < 0) { rc = gnutls_assert_val(CDK_General_Error); goto leave; } params.params_nr = cdk_pk_get_npkey(pk->pubkey_algo); for (i = 0; i < params.params_nr; i++) params.params[i] = pk->mpi[i]; params.flags = 0; ret = _gnutls_pk_verify(algo, &di, &s_sig, ¶ms); if (ret < 0) { gnutls_assert(); rc = map_gnutls_error(ret); goto leave; } rc = 0; leave: _gnutls_free_datum(&s_sig); _gnutls_free_datum(&di); cdk_free(encmd); return rc; }
/* Given a signature and parameters, it should return * the hash algorithm used in the signature. This is a kludge * but until we deprecate gnutls_pubkey_get_verify_algorithm() * we depend on it. */ static int wrap_nettle_hash_algorithm(gnutls_pk_algorithm_t pk, const gnutls_datum_t * sig, gnutls_pk_params_st * issuer_params, gnutls_digest_algorithm_t * hash_algo) { uint8_t digest[MAX_HASH_SIZE]; uint8_t *rdi = NULL; gnutls_datum_t di; unsigned digest_size; mpz_t s; struct rsa_public_key pub; const mac_entry_st *me; int ret; mpz_init(s); switch (pk) { case GNUTLS_PK_DSA: case GNUTLS_PK_EC: me = _gnutls_dsa_q_to_hash(pk, issuer_params, NULL); if (hash_algo) *hash_algo = me->id; ret = 0; break; case GNUTLS_PK_RSA: if (sig == NULL) { /* return a sensible algorithm */ if (hash_algo) *hash_algo = GNUTLS_DIG_SHA256; return 0; } _rsa_params_to_pubkey(issuer_params, &pub); digest_size = sizeof(digest); nettle_mpz_set_str_256_u(s, sig->size, sig->data); ret = extract_digest_info(&pub, &di, &rdi, s); if (ret == 0) { ret = GNUTLS_E_PK_SIG_VERIFY_FAILED; gnutls_assert(); goto cleanup; } digest_size = sizeof(digest); if ((ret = decode_ber_digest_info(&di, hash_algo, digest, &digest_size)) < 0) { gnutls_assert(); goto cleanup; } if (digest_size != _gnutls_hash_get_algo_len(mac_to_entry(*hash_algo))) { gnutls_assert(); ret = GNUTLS_E_PK_SIG_VERIFY_FAILED; goto cleanup; } ret = 0; break; default: gnutls_assert(); ret = GNUTLS_E_INTERNAL_ERROR; } cleanup: mpz_clear(s); gnutls_free(rdi); return ret; }
/** * gnutls_pkcs12_generate_mac: * @pkcs12: should contain a gnutls_pkcs12_t structure * @pass: The password for the MAC * * This function will generate a MAC for the PKCS12 structure. * * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a * negative error value. **/ int gnutls_pkcs12_generate_mac(gnutls_pkcs12_t pkcs12, const char *pass) { uint8_t salt[8], key[20]; int result; const int iter = 1; mac_hd_st td1; gnutls_datum_t tmp = { NULL, 0 }; uint8_t sha_mac[20]; if (pkcs12 == NULL) { gnutls_assert(); return GNUTLS_E_INVALID_REQUEST; } /* Generate the salt. */ result = _gnutls_rnd(GNUTLS_RND_NONCE, salt, sizeof(salt)); if (result < 0) { gnutls_assert(); return result; } /* Write the salt into the structure. */ result = asn1_write_value(pkcs12->pkcs12, "macData.macSalt", salt, sizeof(salt)); if (result != ASN1_SUCCESS) { gnutls_assert(); result = _gnutls_asn2err(result); goto cleanup; } /* write the iterations */ if (iter > 1) { result = _gnutls_x509_write_uint32(pkcs12->pkcs12, "macData.iterations", iter); if (result < 0) { gnutls_assert(); goto cleanup; } } /* Generate the key. */ result = _gnutls_pkcs12_string_to_key(3 /*MAC*/, salt, sizeof(salt), iter, pass, sizeof(key), key); if (result < 0) { gnutls_assert(); goto cleanup; } /* Get the data to be MACed */ result = _decode_pkcs12_auth_safe(pkcs12->pkcs12, NULL, &tmp); if (result < 0) { gnutls_assert(); goto cleanup; } /* MAC the data */ result = _gnutls_mac_init(&td1, mac_to_entry(GNUTLS_MAC_SHA1), key, sizeof(key)); if (result < 0) { gnutls_assert(); goto cleanup; } _gnutls_mac(&td1, tmp.data, tmp.size); _gnutls_free_datum(&tmp); _gnutls_mac_deinit(&td1, sha_mac); result = asn1_write_value(pkcs12->pkcs12, "macData.mac.digest", sha_mac, sizeof(sha_mac)); if (result != ASN1_SUCCESS) { gnutls_assert(); result = _gnutls_asn2err(result); goto cleanup; } result = asn1_write_value(pkcs12->pkcs12, "macData.mac.digestAlgorithm.parameters", NULL, 0); if (result != ASN1_SUCCESS) { gnutls_assert(); result = _gnutls_asn2err(result); goto cleanup; } result = asn1_write_value(pkcs12->pkcs12, "macData.mac.digestAlgorithm.algorithm", HASH_OID_SHA1, 1); if (result != ASN1_SUCCESS) { gnutls_assert(); result = _gnutls_asn2err(result); goto cleanup; } return 0; cleanup: _gnutls_free_datum(&tmp); return result; }
/** * gnutls_pkcs12_verify_mac: * @pkcs12: should contain a gnutls_pkcs12_t structure * @pass: The password for the MAC * * This function will verify the MAC for the PKCS12 structure. * * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a * negative error value. **/ int gnutls_pkcs12_verify_mac(gnutls_pkcs12_t pkcs12, const char *pass) { uint8_t key[20]; int result; unsigned int iter; int len; mac_hd_st td1; gnutls_datum_t tmp = { NULL, 0 }, salt = { NULL, 0}; uint8_t sha_mac[20]; uint8_t sha_mac_orig[20]; if (pkcs12 == NULL) { gnutls_assert(); return GNUTLS_E_INVALID_REQUEST; } /* read the iterations */ result = _gnutls_x509_read_uint(pkcs12->pkcs12, "macData.iterations", &iter); if (result < 0) { iter = 1; /* the default */ } /* Read the salt from the structure. */ result = _gnutls_x509_read_value(pkcs12->pkcs12, "macData.macSalt", &salt); if (result != ASN1_SUCCESS) { gnutls_assert(); result = _gnutls_asn2err(result); goto cleanup; } /* Generate the key. */ result = _gnutls_pkcs12_string_to_key(3 /*MAC*/, salt.data, salt.size, iter, pass, sizeof(key), key); if (result < 0) { gnutls_assert(); goto cleanup; } _gnutls_free_datum(&salt); /* Get the data to be MACed */ result = _decode_pkcs12_auth_safe(pkcs12->pkcs12, NULL, &tmp); if (result < 0) { gnutls_assert(); goto cleanup; } /* MAC the data */ result = _gnutls_mac_init(&td1, mac_to_entry(GNUTLS_MAC_SHA1), key, sizeof(key)); if (result < 0) { gnutls_assert(); goto cleanup; } _gnutls_mac(&td1, tmp.data, tmp.size); _gnutls_free_datum(&tmp); _gnutls_mac_deinit(&td1, sha_mac); len = sizeof(sha_mac_orig); result = asn1_read_value(pkcs12->pkcs12, "macData.mac.digest", sha_mac_orig, &len); if (result != ASN1_SUCCESS) { gnutls_assert(); result = _gnutls_asn2err(result); goto cleanup; } if (memcmp(sha_mac_orig, sha_mac, sizeof(sha_mac)) != 0) { gnutls_assert(); return GNUTLS_E_MAC_VERIFY_FAILED; } return 0; cleanup: _gnutls_free_datum(&tmp); _gnutls_free_datum(&salt); return result; }
static int wrap_padlock_hmac_fast(gnutls_mac_algorithm_t algo, const void *nonce, size_t nonce_size, const void *key, size_t key_size, const void *text, size_t text_size, void *digest) { if (algo == GNUTLS_MAC_SHA1 || algo == GNUTLS_MAC_SHA256) { unsigned char *pad; unsigned char pad2[SHA1_DATA_SIZE + MAX_SHA_DIGEST_SIZE]; unsigned char hkey[MAX_SHA_DIGEST_SIZE]; unsigned int digest_size = _gnutls_mac_get_algo_len(mac_to_entry(algo)); if (key_size > SHA1_DATA_SIZE) { wrap_padlock_hash_fast((gnutls_digest_algorithm_t) algo, key, key_size, hkey); key = hkey; key_size = digest_size; } pad = gnutls_malloc(text_size + SHA1_DATA_SIZE); if (pad == NULL) return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR); memset(pad, IPAD, SHA1_DATA_SIZE); memxor(pad, key, key_size); memcpy(&pad[SHA1_DATA_SIZE], text, text_size); wrap_padlock_hash_fast((gnutls_digest_algorithm_t) algo, pad, text_size + SHA1_DATA_SIZE, &pad2[SHA1_DATA_SIZE]); gnutls_free(pad); memset(pad2, OPAD, SHA1_DATA_SIZE); memxor(pad2, key, key_size); wrap_padlock_hash_fast((gnutls_digest_algorithm_t) algo, pad2, digest_size + SHA1_DATA_SIZE, digest); } else { struct padlock_hmac_ctx ctx; int ret; ret = _hmac_ctx_init(algo, &ctx); if (ret < 0) return gnutls_assert_val(ret); ctx.algo = algo; wrap_padlock_hmac_setkey(&ctx, key, key_size); wrap_padlock_hmac_update(&ctx, text, text_size); wrap_padlock_hmac_output(&ctx, digest, ctx.length); wrap_padlock_hmac_deinit(&ctx); } return 0; }
static int parse_commitment_line(char *line, const char *host, size_t host_len, const char *service, size_t service_len, time_t now, const gnutls_datum_t * skey) { char *p, *kp; char *savep = NULL; size_t kp_len, phash_size; time_t expiration; int ret; const mac_entry_st *hash_algo; uint8_t phash[MAX_HASH_SIZE]; uint8_t hphash[MAX_HASH_SIZE * 2 + 1]; /* read host */ p = strtok_r(line, "|", &savep); if (p == NULL) return gnutls_assert_val(GNUTLS_E_PARSING_ERROR); if (p[0] != '*' && host != NULL && strcmp(p, host) != 0) return gnutls_assert_val(GNUTLS_E_PARSING_ERROR); /* read service */ p = strtok_r(NULL, "|", &savep); if (p == NULL) return gnutls_assert_val(GNUTLS_E_PARSING_ERROR); if (p[0] != '*' && service != NULL && strcmp(p, service) != 0) return gnutls_assert_val(GNUTLS_E_PARSING_ERROR); /* read expiration */ p = strtok_r(NULL, "|", &savep); if (p == NULL) return gnutls_assert_val(GNUTLS_E_PARSING_ERROR); expiration = (time_t) atol(p); if (expiration > 0 && now > expiration) return gnutls_assert_val(GNUTLS_E_EXPIRED); /* read hash algorithm */ p = strtok_r(NULL, "|", &savep); if (p == NULL) return gnutls_assert_val(GNUTLS_E_PARSING_ERROR); hash_algo = mac_to_entry(atol(p)); if (_gnutls_digest_get_name(hash_algo) == NULL) return gnutls_assert_val(GNUTLS_E_PARSING_ERROR); /* read hash */ kp = strtok_r(NULL, "|", &savep); if (kp == NULL) return gnutls_assert_val(GNUTLS_E_PARSING_ERROR); p = strpbrk(kp, "\n \r\t|"); if (p != NULL) *p = 0; /* hash and hex encode */ ret = _gnutls_hash_fast((gnutls_digest_algorithm_t)hash_algo->id, skey->data, skey->size, phash); if (ret < 0) return gnutls_assert_val(ret); phash_size = _gnutls_hash_get_algo_len(hash_algo); p = _gnutls_bin2hex(phash, phash_size, (void *) hphash, sizeof(hphash), NULL); if (p == NULL) return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR); kp_len = strlen(kp); if (kp_len != phash_size * 2) return gnutls_assert_val(GNUTLS_E_CERTIFICATE_KEY_MISMATCH); if (memcmp(kp, hphash, kp_len) != 0) return gnutls_assert_val(GNUTLS_E_CERTIFICATE_KEY_MISMATCH); /* key found and matches */ return 0; }