/* Converts a parsed gnutls_openpgp_crt_t to a gnutls_cert structure. */ int _gnutls_openpgp_crt_to_gcert (gnutls_cert * gcert, gnutls_openpgp_crt_t cert) { int ret; gnutls_openpgp_keyid_t keyid; char err_buf[33]; memset (gcert, 0, sizeof (gnutls_cert)); gcert->cert_type = GNUTLS_CRT_OPENPGP; gcert->version = gnutls_openpgp_crt_get_version (cert); gcert->params_size = MAX_PUBLIC_PARAMS_SIZE; ret = gnutls_openpgp_crt_get_preferred_key_id (cert, keyid); if (ret == 0) { int idx; uint32_t kid32[2]; _gnutls_debug_log ("Importing Openpgp cert and using openpgp sub key: %s\n", _gnutls_bin2hex (keyid, sizeof (keyid), err_buf, sizeof (err_buf))); KEYID_IMPORT (kid32, keyid); idx = gnutls_openpgp_crt_get_subkey_idx (cert, keyid); if (idx < 0) { gnutls_assert (); return idx; } gcert->subject_pk_algorithm = gnutls_openpgp_crt_get_subkey_pk_algorithm (cert, idx, NULL); gnutls_openpgp_crt_get_subkey_usage (cert, idx, &gcert->key_usage); gcert->use_subkey = 1; memcpy (gcert->subkey_id, keyid, sizeof (keyid)); ret = _gnutls_openpgp_crt_get_mpis (cert, kid32, gcert->params, &gcert->params_size); } else { _gnutls_debug_log ("Importing Openpgp cert and using main openpgp key\n"); gcert->subject_pk_algorithm = gnutls_openpgp_crt_get_pk_algorithm (cert, NULL); gnutls_openpgp_crt_get_key_usage (cert, &gcert->key_usage); ret = _gnutls_openpgp_crt_get_mpis (cert, NULL, gcert->params, &gcert->params_size); gcert->use_subkey = 0; } if (ret < 0) { gnutls_assert (); return ret; } { /* copy the raw certificate */ #define SMALL_RAW 512 opaque *raw; size_t raw_size = SMALL_RAW; /* initially allocate a bogus size, just in case the certificate * fits in it. That way we minimize the DER encodings performed. */ raw = gnutls_malloc (raw_size); if (raw == NULL) { gnutls_assert (); return GNUTLS_E_MEMORY_ERROR; } ret = gnutls_openpgp_crt_export (cert, GNUTLS_OPENPGP_FMT_RAW, raw, &raw_size); if (ret < 0 && ret != GNUTLS_E_SHORT_MEMORY_BUFFER) { gnutls_assert (); gnutls_free (raw); return ret; } if (ret == GNUTLS_E_SHORT_MEMORY_BUFFER) { raw = gnutls_realloc (raw, raw_size); if (raw == NULL) { gnutls_assert (); return GNUTLS_E_MEMORY_ERROR; } ret = gnutls_openpgp_crt_export (cert, GNUTLS_OPENPGP_FMT_RAW, raw, &raw_size); if (ret < 0) { gnutls_assert (); gnutls_free (raw); return ret; } } gcert->raw.data = raw; gcert->raw.size = raw_size; } return 0; }
/* Decodes the PKCS #7 signed data, and returns an ASN1_TYPE, * which holds them. If raw is non null then the raw decoded * data are copied (they are locally allocated) there. */ static int _decode_pkcs7_signed_data (ASN1_TYPE pkcs7, ASN1_TYPE * sdata, gnutls_datum_t * raw) { char oid[MAX_OID_SIZE]; ASN1_TYPE c2; uint8_t *tmp = NULL; int tmp_size, len, result; len = sizeof (oid) - 1; result = asn1_read_value (pkcs7, "contentType", oid, &len); if (result != ASN1_SUCCESS) { gnutls_assert (); return _gnutls_asn2err (result); } if (strcmp (oid, SIGNED_DATA_OID) != 0) { gnutls_assert (); _gnutls_debug_log ("Unknown PKCS7 Content OID '%s'\n", oid); return GNUTLS_E_UNKNOWN_PKCS_CONTENT_TYPE; } if ((result = asn1_create_element (_gnutls_get_pkix (), "PKIX1.pkcs-7-SignedData", &c2)) != ASN1_SUCCESS) { gnutls_assert (); return _gnutls_asn2err (result); } /* the Signed-data has been created, so * decode them. */ tmp_size = 0; result = asn1_read_value (pkcs7, "content", NULL, &tmp_size); if (result != ASN1_MEM_ERROR) { gnutls_assert (); result = _gnutls_asn2err (result); goto cleanup; } tmp = gnutls_malloc (tmp_size); if (tmp == NULL) { gnutls_assert (); result = GNUTLS_E_MEMORY_ERROR; goto cleanup; } result = asn1_read_value (pkcs7, "content", tmp, &tmp_size); if (result != ASN1_SUCCESS) { gnutls_assert (); result = _gnutls_asn2err (result); goto cleanup; } /* tmp, tmp_size hold the data and the size of the CertificateSet structure * actually the ANY stuff. */ /* Step 1. In case of a signed structure extract certificate set. */ result = asn1_der_decoding (&c2, tmp, tmp_size, NULL); if (result != ASN1_SUCCESS) { gnutls_assert (); result = _gnutls_asn2err (result); goto cleanup; } if (raw == NULL) { gnutls_free (tmp); } else { raw->data = tmp; raw->size = tmp_size; } *sdata = c2; return 0; cleanup: if (c2) asn1_delete_structure (&c2); gnutls_free (tmp); return result; }
/** * gnutls_x509_trust_list_verify_crt2: * @list: The list * @cert_list: is the certificate list to be verified * @cert_list_size: is the certificate list size * @data: an array of typed data * @elements: the number of data elements * @flags: Flags that may be used to change the verification algorithm. Use OR of the gnutls_certificate_verify_flags enumerations. * @voutput: will hold the certificate verification output. * @func: If non-null will be called on each chain element verification with the output. * * This function will attempt to verify the given certificate chain and return * its status. The @voutput parameter will hold an OR'ed sequence of * %gnutls_certificate_status_t flags. * * When a certificate chain of @cert_list_size with more than one certificates is * provided, the verification status will apply to the first certificate in the chain * that failed verification. The verification process starts from the end of the chain * (from CA to end certificate). The first certificate in the chain must be the end-certificate * while the rest of the members may be sorted or not. * * Additionally a certificate verification profile can be specified * from the ones in %gnutls_certificate_verification_profiles_t by * ORing the result of GNUTLS_PROFILE_TO_VFLAGS() to the verification * flags. * * Additional verification parameters are possible via the @data types; the * acceptable types are %GNUTLS_DT_DNS_HOSTNAME, %GNUTLS_DT_IP_ADDRESS and %GNUTLS_DT_KEY_PURPOSE_OID. * The former accepts as data a null-terminated hostname, and the latter a null-terminated * object identifier (e.g., %GNUTLS_KP_TLS_WWW_SERVER). * If a DNS hostname is provided then this function will compare * the hostname in the end certificate against the given. If names do not match the * %GNUTLS_CERT_UNEXPECTED_OWNER status flag will be set. In addition it * will consider certificates provided with gnutls_x509_trust_list_add_named_crt(). * * If a key purpose OID is provided and the end-certificate contains the extended key * usage PKIX extension, it will be required to match the provided OID * or be marked for any purpose, otherwise verification will fail with * %GNUTLS_CERT_PURPOSE_MISMATCH status. * * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a * negative error value. Note that verification failure will not result to an * error code, only @voutput will be updated. * * Since: 3.3.8 **/ int gnutls_x509_trust_list_verify_crt2(gnutls_x509_trust_list_t list, gnutls_x509_crt_t * cert_list, unsigned int cert_list_size, gnutls_typed_vdata_st *data, unsigned int elements, unsigned int flags, unsigned int *voutput, gnutls_verify_output_function func) { int ret; unsigned int i; uint32_t hash; gnutls_x509_crt_t sorted[DEFAULT_MAX_VERIFY_DEPTH]; const char *hostname = NULL, *purpose = NULL, *email = NULL; unsigned hostname_size = 0; unsigned have_set_name = 0; unsigned saved_output; gnutls_datum_t ip = {NULL, 0}; if (cert_list == NULL || cert_list_size < 1) return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST); for (i=0;i<elements;i++) { if (data[i].type == GNUTLS_DT_DNS_HOSTNAME) { hostname = (void*)data[i].data; if (data[i].size > 0) { hostname_size = data[i].size; } if (have_set_name != 0) return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST); have_set_name = 1; } else if (data[i].type == GNUTLS_DT_IP_ADDRESS) { if (data[i].size > 0) { ip.data = data[i].data; ip.size = data[i].size; } if (have_set_name != 0) return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST); have_set_name = 1; } else if (data[i].type == GNUTLS_DT_RFC822NAME) { email = (void*)data[i].data; if (have_set_name != 0) return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST); have_set_name = 1; } else if (data[i].type == GNUTLS_DT_KEY_PURPOSE_OID) { purpose = (void*)data[i].data; } } if (hostname) { /* shortcut using the named certs - if any */ unsigned vtmp = 0; if (hostname_size == 0) hostname_size = strlen(hostname); ret = gnutls_x509_trust_list_verify_named_crt(list, cert_list[0], hostname, hostname_size, flags, &vtmp, func); if (ret == 0 && vtmp == 0) { *voutput = vtmp; return 0; } } if (!(flags & GNUTLS_VERIFY_DO_NOT_ALLOW_UNSORTED_CHAIN)) cert_list = _gnutls_sort_clist(sorted, cert_list, &cert_list_size, NULL); cert_list_size = shorten_clist(list, cert_list, cert_list_size); if (cert_list_size <= 0) return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR); hash = hash_pjw_bare(cert_list[cert_list_size - 1]->raw_issuer_dn. data, cert_list[cert_list_size - 1]->raw_issuer_dn.size); hash %= list->size; ret = check_if_in_blacklist(cert_list, cert_list_size, list->blacklisted, list->blacklisted_size); if (ret != 0) { *voutput = 0; *voutput |= GNUTLS_CERT_REVOKED; *voutput |= GNUTLS_CERT_INVALID; return 0; } *voutput = _gnutls_verify_crt_status(cert_list, cert_list_size, list->node[hash].trusted_cas, list-> node[hash].trusted_ca_size, flags, purpose, func); saved_output = *voutput; if (SIGNER_OLD_OR_UNKNOWN(*voutput) && (LAST_DN.size != LAST_IDN.size || memcmp(LAST_DN.data, LAST_IDN.data, LAST_IDN.size) != 0)) { /* if we couldn't find the issuer, try to see if the last * certificate is in the trusted list and try to verify against * (if it is not self signed) */ hash = hash_pjw_bare(cert_list[cert_list_size - 1]->raw_dn. data, cert_list[cert_list_size - 1]->raw_dn.size); hash %= list->size; _gnutls_debug_log("issuer in verification was not found or insecure; trying against trust list\n"); *voutput = _gnutls_verify_crt_status(cert_list, cert_list_size, list->node[hash].trusted_cas, list-> node[hash].trusted_ca_size, flags, purpose, func); if (*voutput != 0) { if (SIGNER_WAS_KNOWN(saved_output)) *voutput = saved_output; gnutls_assert(); } } saved_output = *voutput; #ifdef ENABLE_PKCS11 if (SIGNER_OLD_OR_UNKNOWN(*voutput) && list->pkcs11_token) { /* use the token for verification */ *voutput = _gnutls_pkcs11_verify_crt_status(list->pkcs11_token, cert_list, cert_list_size, purpose, flags, func); if (*voutput != 0) { if (SIGNER_WAS_KNOWN(saved_output)) *voutput = saved_output; gnutls_assert(); } } #endif /* End-certificate, key purpose and hostname checks. */ if (purpose) { ret = _gnutls_check_key_purpose(cert_list[0], purpose, 0); if (ret != 1) { gnutls_assert(); *voutput |= GNUTLS_CERT_PURPOSE_MISMATCH|GNUTLS_CERT_INVALID; } } if (hostname) { ret = gnutls_x509_crt_check_hostname2(cert_list[0], hostname, flags); if (ret == 0) { gnutls_assert(); *voutput |= GNUTLS_CERT_UNEXPECTED_OWNER|GNUTLS_CERT_INVALID; } } if (ip.data) { ret = gnutls_x509_crt_check_ip(cert_list[0], ip.data, ip.size, flags); if (ret == 0) { gnutls_assert(); *voutput |= GNUTLS_CERT_UNEXPECTED_OWNER|GNUTLS_CERT_INVALID; } } if (email) { ret = gnutls_x509_crt_check_email(cert_list[0], email, 0); if (ret == 0) { gnutls_assert(); *voutput |= GNUTLS_CERT_UNEXPECTED_OWNER|GNUTLS_CERT_INVALID; } } /* CRL checks follow */ if (*voutput != 0 || (flags & GNUTLS_VERIFY_DISABLE_CRL_CHECKS)) return 0; /* Check revocation of individual certificates. * start with the last one that we already have its hash */ ret = _gnutls_x509_crt_check_revocation(cert_list [cert_list_size - 1], list->node[hash].crls, list->node[hash].crl_size, func); if (ret == 1) { /* revoked */ *voutput |= GNUTLS_CERT_REVOKED; *voutput |= GNUTLS_CERT_INVALID; return 0; } for (i = 0; i < cert_list_size - 1; i++) { hash = hash_pjw_bare(cert_list[i]->raw_issuer_dn.data, cert_list[i]->raw_issuer_dn.size); hash %= list->size; ret = _gnutls_x509_crt_check_revocation(cert_list[i], list->node[hash]. crls, list->node[hash]. crl_size, func); if (ret < 0) { gnutls_assert(); } else if (ret == 1) { /* revoked */ *voutput |= GNUTLS_CERT_REVOKED; *voutput |= GNUTLS_CERT_INVALID; return 0; } } return 0; }
/** * gnutls_pkcs11_privkey_generate: * @url: a token URL * @pk: the public key algorithm * @bits: the security bits * @label: a label * @flags: should be zero * * This function will generate a private key in the specified * by the @url token. The pivate key will be generate within * the token and will not be exportable. * * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a * negative error value. * * Since: 3.0 **/ int gnutls_pkcs11_privkey_generate (const char* url, gnutls_pk_algorithm_t pk, unsigned int bits, const char* label, unsigned int flags) { int ret; const ck_bool_t tval = 1; const ck_bool_t fval = 0; struct ck_function_list *module; ck_session_handle_t pks = 0; struct p11_kit_uri *info = NULL; ck_rv_t rv; struct ck_attribute a[10], p[10]; ck_object_handle_t pub, priv; unsigned long _bits = bits; int a_val, p_val; struct ck_mechanism mech; ret = pkcs11_url_to_info (url, &info); if (ret < 0) { gnutls_assert (); return ret; } ret = pkcs11_open_session (&module, &pks, info, SESSION_WRITE | pkcs11_obj_flags_to_int (flags)); p11_kit_uri_free (info); if (ret < 0) { gnutls_assert (); goto cleanup; } /* a holds the public key template * and p the private key */ a_val = p_val = 0; mech.parameter = NULL; mech.parameter_len = 0; mech.mechanism = pk_to_genmech(pk); switch(pk) { case GNUTLS_PK_RSA: p[p_val].type = CKA_DECRYPT; p[p_val].value = (void*)&tval; p[p_val].value_len = sizeof (tval); p_val++; p[p_val].type = CKA_SIGN; p[p_val].value = (void*)&tval; p[p_val].value_len = sizeof (tval); p_val++; a[a_val].type = CKA_ENCRYPT; a[a_val].value = (void*)&tval; a[a_val].value_len = sizeof (tval); a_val++; a[a_val].type = CKA_VERIFY; a[a_val].value = (void*)&tval; a[a_val].value_len = sizeof (tval); a_val++; a[a_val].type = CKA_MODULUS_BITS; a[a_val].value = &_bits; a[a_val].value_len = sizeof (_bits); a_val++; break; case GNUTLS_PK_DSA: p[p_val].type = CKA_SIGN; p[p_val].value = (void*)&tval; p[p_val].value_len = sizeof (tval); p_val++; a[a_val].type = CKA_VERIFY; a[a_val].value = (void*)&tval; a[a_val].value_len = sizeof (tval); a_val++; a[a_val].type = CKA_MODULUS_BITS; a[a_val].value = &_bits; a[a_val].value_len = sizeof (_bits); a_val++; break; case GNUTLS_PK_EC: p[p_val].type = CKA_SIGN; p[p_val].value = (void*)&tval; p[p_val].value_len = sizeof (tval); p_val++; a[a_val].type = CKA_VERIFY; a[a_val].value = (void*)&tval; a[a_val].value_len = sizeof (tval); a_val++; a[a_val].type = CKA_MODULUS_BITS; a[a_val].value = &_bits; a[a_val].value_len = sizeof (_bits); a_val++; break; default: ret = gnutls_assert_val(GNUTLS_E_INVALID_REQUEST); goto cleanup; } /* a private key is set always as private unless * requested otherwise */ if (flags & GNUTLS_PKCS11_OBJ_FLAG_MARK_NOT_PRIVATE) { p[p_val].type = CKA_PRIVATE; p[p_val].value = (void*)&fval; p[p_val].value_len = sizeof(fval); p_val++; } else { p[p_val].type = CKA_PRIVATE; p[p_val].value = (void*)&tval; p[p_val].value_len = sizeof (tval); p_val++; } p[p_val].type = CKA_TOKEN; p[p_val].value = (void *)&tval; p[p_val].value_len = sizeof (tval); p_val++; if (label) { p[p_val].type = CKA_LABEL; p[p_val].value = (void*)label; p[p_val].value_len = strlen (label); p_val++; a[a_val].type = CKA_LABEL; a[a_val].value = (void*)label; a[a_val].value_len = strlen (label); a_val++; } if (flags & GNUTLS_PKCS11_OBJ_FLAG_MARK_SENSITIVE) { p[p_val].type = CKA_SENSITIVE; p[p_val].value = (void*)&tval; p[p_val].value_len = sizeof (tval); p_val++; } else { p[p_val].type = CKA_SENSITIVE; p[p_val].value = (void*)&fval; p[p_val].value_len = sizeof (fval); p_val++; } rv = pkcs11_generate_key_pair( module, pks, &mech, a, a_val, p, p_val, &pub, &priv); if (rv != CKR_OK) { gnutls_assert (); _gnutls_debug_log ("pkcs11: %s\n", pkcs11_strerror (rv)); ret = pkcs11_rv_to_err (rv); goto cleanup; } cleanup: if (pks != 0) pkcs11_close_session (module, pks); return ret; }
/* Decodes the PKCS #12 auth_safe, and returns the allocated raw data, * which holds them. Returns an ASN1_TYPE of authenticatedSafe. */ static int _decode_pkcs12_auth_safe(ASN1_TYPE pkcs12, ASN1_TYPE * authen_safe, gnutls_datum_t * raw) { char oid[MAX_OID_SIZE]; ASN1_TYPE c2 = ASN1_TYPE_EMPTY; gnutls_datum_t auth_safe = { NULL, 0 }; int len, result; char error_str[ASN1_MAX_ERROR_DESCRIPTION_SIZE]; len = sizeof(oid) - 1; result = asn1_read_value(pkcs12, "authSafe.contentType", oid, &len); if (result != ASN1_SUCCESS) { gnutls_assert(); return _gnutls_asn2err(result); } if (strcmp(oid, DATA_OID) != 0) { gnutls_assert(); _gnutls_debug_log("Unknown PKCS12 Content OID '%s'\n", oid); return GNUTLS_E_UNKNOWN_PKCS_CONTENT_TYPE; } /* Step 1. Read the content data */ result = _gnutls_x509_read_string(pkcs12, "authSafe.content", &auth_safe, ASN1_ETYPE_OCTET_STRING); if (result < 0) { gnutls_assert(); goto cleanup; } /* Step 2. Extract the authenticatedSafe. */ if ((result = asn1_create_element (_gnutls_get_pkix(), "PKIX1.pkcs-12-AuthenticatedSafe", &c2)) != ASN1_SUCCESS) { gnutls_assert(); result = _gnutls_asn2err(result); goto cleanup; } result = asn1_der_decoding(&c2, auth_safe.data, auth_safe.size, error_str); if (result != ASN1_SUCCESS) { gnutls_assert(); _gnutls_debug_log("DER error: %s\n", error_str); result = _gnutls_asn2err(result); goto cleanup; } if (raw == NULL) { _gnutls_free_datum(&auth_safe); } else { raw->data = auth_safe.data; raw->size = auth_safe.size; } if (authen_safe) *authen_safe = c2; else asn1_delete_structure(&c2); return 0; cleanup: if (c2) asn1_delete_structure(&c2); _gnutls_free_datum(&auth_safe); return result; }
/* in case of DSA puts into data, r,s */ static int _wrap_nettle_pk_sign(gnutls_pk_algorithm_t algo, gnutls_datum_t * signature, const gnutls_datum_t * vdata, const gnutls_pk_params_st * pk_params) { int ret; unsigned int hash_len; const mac_entry_st *me; switch (algo) { case GNUTLS_PK_EC: /* we do ECDSA */ { struct ecc_scalar priv; struct dsa_signature sig; int curve_id = pk_params->flags; const struct ecc_curve *curve; curve = get_supported_curve(curve_id); if (curve == NULL) return gnutls_assert_val (GNUTLS_E_ECC_UNSUPPORTED_CURVE); ret = _ecc_params_to_privkey(pk_params, &priv, curve); if (ret < 0) return gnutls_assert_val(ret); dsa_signature_init(&sig); me = _gnutls_dsa_q_to_hash(algo, pk_params, &hash_len); if (hash_len > vdata->size) { gnutls_assert(); _gnutls_debug_log ("Security level of algorithm requires hash %s(%d) or better\n", _gnutls_mac_get_name(me), hash_len); hash_len = vdata->size; } ecdsa_sign(&priv, NULL, rnd_func, hash_len, vdata->data, &sig); ret = _gnutls_encode_ber_rs(signature, &sig.r, &sig.s); dsa_signature_clear(&sig); ecc_scalar_clear(&priv); if (ret < 0) { gnutls_assert(); goto cleanup; } break; } case GNUTLS_PK_DSA: { struct dsa_public_key pub; struct dsa_private_key priv; struct dsa_signature sig; memset(&priv, 0, sizeof(priv)); memset(&pub, 0, sizeof(pub)); _dsa_params_to_pubkey(pk_params, &pub); _dsa_params_to_privkey(pk_params, &priv); dsa_signature_init(&sig); me = _gnutls_dsa_q_to_hash(algo, pk_params, &hash_len); if (hash_len > vdata->size) { gnutls_assert(); _gnutls_debug_log ("Security level of algorithm requires hash %s(%d) or better\n", _gnutls_mac_get_name(me), hash_len); hash_len = vdata->size; } ret = _dsa_sign(&pub, &priv, NULL, rnd_func, hash_len, vdata->data, &sig); if (ret == 0) { gnutls_assert(); ret = GNUTLS_E_PK_SIGN_FAILED; goto dsa_fail; } ret = _gnutls_encode_ber_rs(signature, &sig.r, &sig.s); dsa_fail: dsa_signature_clear(&sig); if (ret < 0) { gnutls_assert(); goto cleanup; } break; } case GNUTLS_PK_RSA: { struct rsa_private_key priv; struct rsa_public_key pub; mpz_t s; _rsa_params_to_privkey(pk_params, &priv); _rsa_params_to_pubkey(pk_params, &pub); mpz_init(s); ret = rsa_pkcs1_sign_tr(&pub, &priv, NULL, rnd_func, vdata->size, vdata->data, s); if (ret == 0) { gnutls_assert(); ret = GNUTLS_E_PK_SIGN_FAILED; goto rsa_fail; } ret = _gnutls_mpi_dprint_size(s, signature, pub.size); rsa_fail: mpz_clear(s); if (ret < 0) { gnutls_assert(); goto cleanup; } break; } default: gnutls_assert(); ret = GNUTLS_E_INTERNAL_ERROR; goto cleanup; } ret = 0; cleanup: return ret; }
/** * gnutls_dh_params_import_pkcs3: * @params: A structure where the parameters will be copied to * @pkcs3_params: should contain a PKCS3 DHParams structure PEM or DER encoded * @format: the format of params. PEM or DER. * * This function will extract the DHParams found in a PKCS3 formatted * structure. This is the format generated by "openssl dhparam" tool. * * If the structure is PEM encoded, it should have a header * of "BEGIN DH PARAMETERS". * * Returns: On success, %GNUTLS_E_SUCCESS (zero) is returned, * otherwise an error code is returned. **/ int gnutls_dh_params_import_pkcs3 (gnutls_dh_params_t params, const gnutls_datum_t * pkcs3_params, gnutls_x509_crt_fmt_t format) { ASN1_TYPE c2; int result, need_free = 0; gnutls_datum_t _params; if (format == GNUTLS_X509_FMT_PEM) { opaque *out; result = _gnutls_fbase64_decode ("DH PARAMETERS", pkcs3_params->data, pkcs3_params->size, &out); if (result <= 0) { if (result == 0) result = GNUTLS_E_INTERNAL_ERROR; gnutls_assert (); return result; } _params.data = out; _params.size = result; need_free = 1; } else { _params.data = pkcs3_params->data; _params.size = pkcs3_params->size; } if ((result = asn1_create_element (_gnutls_get_gnutls_asn (), "GNUTLS.DHParameter", &c2)) != ASN1_SUCCESS) { gnutls_assert (); if (need_free != 0) { gnutls_free (_params.data); _params.data = NULL; } return _gnutls_asn2err (result); } result = asn1_der_decoding (&c2, _params.data, _params.size, NULL); if (need_free != 0) { gnutls_free (_params.data); _params.data = NULL; } if (result != ASN1_SUCCESS) { /* couldn't decode DER */ _gnutls_debug_log ("DHParams: Decoding error %d\n", result); gnutls_assert (); asn1_delete_structure (&c2); return _gnutls_asn2err (result); } /* Read PRIME */ result = _gnutls_x509_read_int (c2, "prime", ¶ms->params[0]); if (result < 0) { asn1_delete_structure (&c2); gnutls_assert (); return result; } /* read the generator */ result = _gnutls_x509_read_int (c2, "base", ¶ms->params[1]); if (result < 0) { asn1_delete_structure (&c2); _gnutls_mpi_release (¶ms->params[0]); gnutls_assert (); return result; } asn1_delete_structure (&c2); return 0; }
static int capi_sign(gnutls_privkey_t key, void *userdata, const gnutls_datum_t * raw_data, gnutls_datum_t * signature) { priv_st *priv = (priv_st *) userdata; ALG_ID Algid; HCRYPTHASH hHash = NULL; uint8_t digest[MAX_HASH_SIZE]; unsigned int digest_size; gnutls_digest_algorithm_t algo; DWORD size1 = 0, sizesize = sizeof(DWORD); DWORD ret_sig = 0; int ret; signature->data = NULL; signature->size = 0; digest_size = raw_data->size; switch (digest_size) { case 16: Algid = CALG_MD5; break; //case 35: size=20; // DigestInfo SHA1 case 20: Algid = CALG_SHA1; break; //case 51: size=32; // DigestInto SHA-256 case 32: Algid = CALG_SHA_256; break; case 36: Algid = CALG_SSL3_SHAMD5; break; case 48: Algid = CALG_SHA_384; break; case 64: Algid = CALG_SHA_512; break; default: digest_size = sizeof(digest); ret = decode_ber_digest_info(raw_data, &algo, digest, &digest_size); if (ret < 0) return gnutls_assert_val(ret); switch (algo) { case GNUTLS_DIG_SHA1: Algid = CALG_SHA1; break; #ifdef NCRYPT_SHA224_ALGORITHM case GNUTLS_DIG_SHA224: Algid = CALG_SHA_224; break; #endif case GNUTLS_DIG_SHA256: Algid = CALG_SHA_256; break; case GNUTLS_DIG_SHA384: Algid = CALG_SHA_384; break; case GNUTLS_DIG_SHA512: Algid = CALG_SHA_512; break; default: return gnutls_assert_val(GNUTLS_E_UNKNOWN_HASH_ALGORITHM); } } if (!CryptCreateHash(priv->hCryptProv, Algid, 0, 0, &hHash)) { gnutls_assert(); _gnutls_debug_log("error in create hash: %d\n", (int)GetLastError()); ret = GNUTLS_E_PK_SIGN_FAILED; goto fail; } if (!CryptSetHashParam(hHash, HP_HASHVAL, digest, 0)) { gnutls_assert(); _gnutls_debug_log("error in set hash val: %d\n", (int)GetLastError()); ret = GNUTLS_E_PK_SIGN_FAILED; goto fail; } if (!CryptGetHashParam (hHash, HP_HASHSIZE, (BYTE *) & size1, &sizesize, 0) || digest_size != size1) { gnutls_assert(); _gnutls_debug_log("error in hash size: %d\n", (int)size1); ret = GNUTLS_E_PK_SIGN_FAILED; goto fail; } if (!CryptSignHash(hHash, priv->dwKeySpec, NULL, 0, NULL, &ret_sig)) { gnutls_assert(); _gnutls_debug_log("error in pre-signing: %d\n", (int)GetLastError()); ret = GNUTLS_E_PK_SIGN_FAILED; goto fail; } signature->size = ret_sig; signature->data = (unsigned char *)gnutls_malloc(signature->size); if (signature->data == NULL) return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR); if (!CryptSignHash (hHash, priv->dwKeySpec, NULL, 0, signature->data, &ret_sig)) { gnutls_assert(); _gnutls_debug_log("error in signing: %d\n", (int)GetLastError()); ret = GNUTLS_E_PK_SIGN_FAILED; goto fail; } memrev(signature->data, signature->size); CryptDestroyHash(hHash); signature->size = ret_sig; return 0; fail: if (hHash != 0) CryptDestroyHash(hHash); gnutls_free(signature->data); return ret; }
static int cng_sign(gnutls_privkey_t key, void *userdata, const gnutls_datum_t * raw_data, gnutls_datum_t * signature) { priv_st *priv = userdata; BCRYPT_PKCS1_PADDING_INFO _info; void *info = NULL; DWORD ret_sig = 0; int ret; DWORD flags = 0; gnutls_datum_t data = { raw_data->data, raw_data->size }; uint8_t digest[MAX_HASH_SIZE]; unsigned int digest_size; gnutls_digest_algorithm_t algo; SECURITY_STATUS r; signature->data = NULL; signature->size = 0; if (priv->pk == GNUTLS_PK_RSA) { flags = BCRYPT_PAD_PKCS1; info = &_info; if (raw_data->size == 36) { /* TLS 1.0 MD5+SHA1 */ _info.pszAlgId = NULL; } else { digest_size = sizeof(digest); ret = decode_ber_digest_info(raw_data, &algo, digest, &digest_size); if (ret < 0) return gnutls_assert_val(ret); switch (algo) { case GNUTLS_DIG_SHA1: _info.pszAlgId = NCRYPT_SHA1_ALGORITHM; break; #ifdef NCRYPT_SHA224_ALGORITHM case GNUTLS_DIG_SHA224: _info.pszAlgId = NCRYPT_SHA224_ALGORITHM; break; #endif case GNUTLS_DIG_SHA256: _info.pszAlgId = NCRYPT_SHA256_ALGORITHM; break; case GNUTLS_DIG_SHA384: _info.pszAlgId = NCRYPT_SHA384_ALGORITHM; break; case GNUTLS_DIG_SHA512: _info.pszAlgId = NCRYPT_SHA512_ALGORITHM; break; default: return gnutls_assert_val (GNUTLS_E_UNKNOWN_HASH_ALGORITHM); } data.data = digest; data.size = digest_size; } } r = pNCryptSignHash(priv->nc, info, data.data, data.size, NULL, 0, &ret_sig, flags); if (FAILED(r)) { gnutls_assert(); _gnutls_debug_log("error in pre-signing: %d\n", (int)GetLastError()); ret = GNUTLS_E_PK_SIGN_FAILED; goto fail; } signature->size = ret_sig; signature->data = gnutls_malloc(signature->size); if (signature->data == NULL) return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR); r = pNCryptSignHash(priv->nc, info, data.data, data.size, signature->data, signature->size, &ret_sig, flags); if (FAILED(r)) { gnutls_assert(); _gnutls_debug_log("error in signing: %d\n", (int)GetLastError()); ret = GNUTLS_E_PK_SIGN_FAILED; goto fail; } signature->size = ret_sig; return 0; fail: gnutls_free(signature->data); return ret; }
/* Run an HMAC using the key above on the library binary data. * Returns true on success and false on error. */ static unsigned check_binary_integrity(const char* libname, const char* symbol) { int ret; unsigned prev; char mac_file[GNUTLS_PATH_MAX]; char file[GNUTLS_PATH_MAX]; uint8_t hmac[HMAC_SIZE]; uint8_t new_hmac[HMAC_SIZE]; size_t hmac_size; gnutls_datum_t data; ret = get_library_path(libname, symbol, file, sizeof(file)); if (ret < 0) { _gnutls_debug_log("Could not get path for library %s\n", libname); return 0; } _gnutls_debug_log("Loading: %s\n", file); ret = gnutls_load_file(file, &data); if (ret < 0) { _gnutls_debug_log("Could not load: %s\n", file); return gnutls_assert_val(0); } prev = _gnutls_get_lib_state(); _gnutls_switch_lib_state(LIB_STATE_OPERATIONAL); ret = gnutls_hmac_fast(HMAC_ALGO, FIPS_KEY, sizeof(FIPS_KEY)-1, data.data, data.size, new_hmac); _gnutls_switch_lib_state(prev); gnutls_free(data.data); if (ret < 0) return gnutls_assert_val(0); /* now open the .hmac file and compare */ get_hmac_file(mac_file, sizeof(mac_file), file); ret = gnutls_load_file(mac_file, &data); if (ret < 0) { get_hmac_file2(mac_file, sizeof(mac_file), file); ret = gnutls_load_file(mac_file, &data); if (ret < 0) { _gnutls_debug_log("Could not open %s for MAC testing: %s\n", mac_file, gnutls_strerror(ret)); return gnutls_assert_val(0); } } hmac_size = hex_data_size(data.size); ret = gnutls_hex_decode(&data, hmac, &hmac_size); gnutls_free(data.data); if (ret < 0) { _gnutls_debug_log("Could not convert hex data to binary for MAC testing for %s.\n", libname); return gnutls_assert_val(0); } if (hmac_size != sizeof(hmac) || memcmp(hmac, new_hmac, sizeof(hmac)) != 0) { _gnutls_debug_log("Calculated MAC for %s does not match\n", libname); return gnutls_assert_val(0); } _gnutls_debug_log("Successfully verified MAC for %s (%s)\n", mac_file, libname); return 1; }
/*- * _gnutls_privkey_import_system: * @pkey: The private key * @url: The URL of the key * * This function will import the given private key to the abstract * #gnutls_privkey_t type. * * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a * negative error value. * * Since: 3.4.0 * -*/ int _gnutls_privkey_import_system_url(gnutls_privkey_t pkey, const char *url) { uint8_t id[MAX_WID_SIZE]; HCERTSTORE store = NULL; size_t id_size; const CERT_CONTEXT *cert = NULL; CRYPT_HASH_BLOB blob; CRYPT_KEY_PROV_INFO *kpi = NULL; NCRYPT_KEY_HANDLE nc = NULL; NCRYPT_PROV_HANDLE sctx = NULL; DWORD kpi_size; SECURITY_STATUS r; int ret, enc_too = 0; WCHAR algo_str[64]; DWORD algo_str_size = 0; priv_st *priv; if (ncrypt_init == 0) return gnutls_assert_val(GNUTLS_E_UNIMPLEMENTED_FEATURE); if (url == NULL) return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST); priv = gnutls_calloc(1, sizeof(*priv)); if (priv == NULL) return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR); id_size = sizeof(id); ret = get_id(url, id, &id_size, 0); if (ret < 0) return gnutls_assert_val(ret); blob.cbData = id_size; blob.pbData = id; store = CertOpenSystemStore(0, "MY"); if (store == NULL) { gnutls_assert(); ret = GNUTLS_E_FILE_ERROR; goto cleanup; } cert = CertFindCertificateInStore(store, X509_ASN_ENCODING, 0, CERT_FIND_KEY_IDENTIFIER, &blob, NULL); if (cert == NULL) { char buf[64]; _gnutls_debug_log("cannot find ID: %s from %s\n", _gnutls_bin2hex(id, id_size, buf, sizeof(buf), NULL), url); ret = gnutls_assert_val(GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE); goto cleanup; } kpi_size = 0; r = CertGetCertificateContextProperty(cert, CERT_KEY_PROV_INFO_PROP_ID, NULL, &kpi_size); if (r == 0) { _gnutls_debug_log("error in getting context: %d from %s\n", (int)GetLastError(), url); ret = gnutls_assert_val(GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE); goto cleanup; } kpi = gnutls_malloc(kpi_size); if (kpi == NULL) { gnutls_assert(); ret = GNUTLS_E_MEMORY_ERROR; goto cleanup; } r = CertGetCertificateContextProperty(cert, CERT_KEY_PROV_INFO_PROP_ID, kpi, &kpi_size); if (r == 0) { _gnutls_debug_log("error in getting context: %d from %s\n", (int)GetLastError(), url); ret = gnutls_assert_val(GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE); goto cleanup; } r = pNCryptOpenStorageProvider(&sctx, kpi->pwszProvName, 0); if (FAILED(r)) { ret = gnutls_assert_val(GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE); goto cleanup; } r = pNCryptOpenKey(sctx, &nc, kpi->pwszContainerName, 0, 0); if (FAILED(r)) { ret = gnutls_assert_val(GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE); goto cleanup; } r = pNCryptGetProperty(nc, NCRYPT_ALGORITHM_PROPERTY, (BYTE*)algo_str, sizeof(algo_str), &algo_str_size, 0); if (FAILED(r)) { ret = gnutls_assert_val(GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE); goto cleanup; } if (StrCmpW(algo_str, BCRYPT_RSA_ALGORITHM) == 0) { priv->pk = GNUTLS_PK_RSA; priv->sign_algo = GNUTLS_SIGN_RSA_SHA256; enc_too = 1; } else if (StrCmpW(algo_str, BCRYPT_DSA_ALGORITHM) == 0) { priv->pk = GNUTLS_PK_DSA; priv->sign_algo = GNUTLS_SIGN_DSA_SHA1; } else if (StrCmpW(algo_str, BCRYPT_ECDSA_P256_ALGORITHM) == 0) { priv->pk = GNUTLS_PK_EC; priv->sign_algo = GNUTLS_SIGN_ECDSA_SHA256; } else if (StrCmpW(algo_str, BCRYPT_ECDSA_P384_ALGORITHM) == 0) { priv->pk = GNUTLS_PK_EC; priv->sign_algo = GNUTLS_SIGN_ECDSA_SHA384; } else if (StrCmpW(algo_str, BCRYPT_ECDSA_P521_ALGORITHM) == 0) { priv->pk = GNUTLS_PK_EC; priv->sign_algo = GNUTLS_SIGN_ECDSA_SHA512; } else { _gnutls_debug_log("unknown key algorithm: %ls\n", algo_str); ret = gnutls_assert_val(GNUTLS_E_UNKNOWN_PK_ALGORITHM); goto cleanup; } priv->nc = nc; ret = gnutls_privkey_import_ext3(pkey, priv, cng_sign, (enc_too!=0)?cng_decrypt:NULL, cng_deinit, cng_info, 0); if (ret < 0) { gnutls_assert(); goto cleanup; } ret = 0; cleanup: if (ret < 0) { if (nc != 0) pNCryptFreeObject(nc); gnutls_free(priv); } if (sctx != 0) pNCryptFreeObject(sctx); gnutls_free(kpi); CertCloseStore(store, 0); return ret; }
void register_padlock_crypto (void) { int ret, phe; if (check_via () == 0) return; if (check_padlock ()) { _gnutls_debug_log ("Padlock AES accelerator was detected\n"); ret = gnutls_crypto_single_cipher_register (GNUTLS_CIPHER_AES_128_CBC, 80, &aes_padlock_struct); if (ret < 0) { gnutls_assert (); } /* register GCM ciphers */ ret = gnutls_crypto_single_cipher_register (GNUTLS_CIPHER_AES_128_GCM, 80, &aes_gcm_padlock_struct); if (ret < 0) { gnutls_assert (); } #ifdef HAVE_LIBNETTLE ret = gnutls_crypto_single_cipher_register (GNUTLS_CIPHER_AES_192_CBC, 80, &aes_padlock_struct); if (ret < 0) { gnutls_assert (); } ret = gnutls_crypto_single_cipher_register (GNUTLS_CIPHER_AES_256_CBC, 80, &aes_padlock_struct); if (ret < 0) { gnutls_assert (); } ret = gnutls_crypto_single_cipher_register (GNUTLS_CIPHER_AES_256_GCM, 80, &aes_gcm_padlock_struct); if (ret < 0) { gnutls_assert (); } #endif } #ifdef HAVE_LIBNETTLE phe = check_phe (); if (phe && check_phe_partial ()) { _gnutls_debug_log ("Padlock SHA1 and SHA256 (partial) accelerator was detected\n"); if (check_phe_sha512 ()) { _gnutls_debug_log ("Padlock SHA512 (partial) accelerator was detected\n"); ret = gnutls_crypto_single_digest_register (GNUTLS_DIG_SHA384, 80, &sha_padlock_nano_struct); if (ret < 0) { gnutls_assert (); } ret = gnutls_crypto_single_digest_register (GNUTLS_DIG_SHA512, 80, &sha_padlock_nano_struct); if (ret < 0) { gnutls_assert (); } ret = gnutls_crypto_single_mac_register (GNUTLS_MAC_SHA384, 80, &hmac_sha_padlock_nano_struct); if (ret < 0) { gnutls_assert (); } ret = gnutls_crypto_single_mac_register (GNUTLS_MAC_SHA512, 80, &hmac_sha_padlock_nano_struct); if (ret < 0) { gnutls_assert (); } } ret = gnutls_crypto_single_digest_register (GNUTLS_DIG_SHA1, 80, &sha_padlock_nano_struct); if (ret < 0) { gnutls_assert (); } ret = gnutls_crypto_single_digest_register (GNUTLS_DIG_SHA224, 80, &sha_padlock_nano_struct); if (ret < 0) { gnutls_assert (); } ret = gnutls_crypto_single_digest_register (GNUTLS_DIG_SHA256, 80, &sha_padlock_nano_struct); if (ret < 0) { gnutls_assert (); } ret = gnutls_crypto_single_mac_register (GNUTLS_MAC_SHA1, 80, &hmac_sha_padlock_nano_struct); if (ret < 0) { gnutls_assert (); } /* we don't register MAC_SHA224 because it is not used by TLS */ ret = gnutls_crypto_single_mac_register (GNUTLS_MAC_SHA256, 80, &hmac_sha_padlock_nano_struct); if (ret < 0) { gnutls_assert (); } } else if (phe) { /* Original padlock PHE. Does not support incremental operations. */ _gnutls_debug_log ("Padlock SHA1 and SHA256 accelerator was detected\n"); ret = gnutls_crypto_single_digest_register (GNUTLS_DIG_SHA1, 80, &sha_padlock_struct); if (ret < 0) { gnutls_assert (); } ret = gnutls_crypto_single_digest_register (GNUTLS_DIG_SHA256, 80, &sha_padlock_struct); if (ret < 0) { gnutls_assert (); } ret = gnutls_crypto_single_mac_register (GNUTLS_MAC_SHA1, 80, &hmac_sha_padlock_struct); if (ret < 0) { gnutls_assert (); } ret = gnutls_crypto_single_mac_register (GNUTLS_MAC_SHA256, 80, &hmac_sha_padlock_struct); if (ret < 0) { gnutls_assert (); } } #endif return; }
int _gnutls_ucs2_to_utf8(const void *data, size_t size, gnutls_datum_t * output, unsigned be) { int ret; unsigned i; int len = 0, src_len; char *dst = NULL; char *src = NULL; static unsigned flags = 0; static int checked = 0; if (checked == 0) { /* Not all windows versions support MB_ERR_INVALID_CHARS */ ret = WideCharToMultiByte(CP_UTF8, MB_ERR_INVALID_CHARS, L"hello", -1, NULL, 0, NULL, NULL); if (ret > 0) flags = MB_ERR_INVALID_CHARS; checked = 1; } if (((uint8_t *) data)[size] == 0 && ((uint8_t *) data)[size+1] == 0) { size -= 2; } src = gnutls_malloc(size+2); if (src == NULL) return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR); /* convert to LE */ if (be) { for (i = 0; i < size; i += 2) { src[i] = ((uint8_t *) data)[1 + i]; src[1 + i] = ((uint8_t *) data)[i]; } } else { memcpy(src, data, size); } src[size] = 0; src[size+1] = 0; src_len = wcslen(src); ret = WideCharToMultiByte(CP_UTF8, flags, (void *) src, src_len, NULL, 0, NULL, NULL); if (ret == 0) { _gnutls_debug_log("WideCharToMultiByte: %d\n", (int)GetLastError()); ret = gnutls_assert_val(GNUTLS_E_PARSING_ERROR); goto fail; } len = ret + 1; dst = gnutls_malloc(len); if (dst == NULL) { ret = gnutls_assert_val(GNUTLS_E_MEMORY_ERROR); goto fail; } dst[0] = 0; ret = WideCharToMultiByte(CP_UTF8, flags, (void *) src, src_len, dst, len-1, NULL, NULL); if (ret == 0) { ret = gnutls_assert_val(GNUTLS_E_PARSING_ERROR); goto fail; } dst[len - 1] = 0; output->data = dst; output->size = ret; ret = 0; goto cleanup; fail: gnutls_free(dst); cleanup: gnutls_free(src); return ret; }
static int add_system_trust(gnutls_x509_trust_list_t list, unsigned int tl_flags, unsigned int tl_vflags) { char path[GNUTLS_PATH_MAX]; unsigned int i; int r = 0; for (i = 0; i < 2; i++) { HCERTSTORE store; const CERT_CONTEXT *cert; const CRL_CONTEXT *crl; gnutls_datum_t data; if (i == 0) store = CertOpenSystemStore(0, "ROOT"); else store = CertOpenSystemStore(0, "CA"); if (store == NULL) return GNUTLS_E_FILE_ERROR; cert = CertEnumCertificatesInStore(store, NULL); crl = pCertEnumCRLsInStore(store, NULL); while (cert != NULL) { if (cert->dwCertEncodingType == X509_ASN_ENCODING) { data.data = cert->pbCertEncoded; data.size = cert->cbCertEncoded; if (gnutls_x509_trust_list_add_trust_mem (list, &data, NULL, GNUTLS_X509_FMT_DER, tl_flags, tl_vflags) > 0) r++; } cert = CertEnumCertificatesInStore(store, cert); } while (crl != NULL) { if (crl->dwCertEncodingType == X509_ASN_ENCODING) { data.data = crl->pbCrlEncoded; data.size = crl->cbCrlEncoded; gnutls_x509_trust_list_add_trust_mem(list, NULL, &data, GNUTLS_X509_FMT_DER, tl_flags, tl_vflags); } crl = pCertEnumCRLsInStore(store, crl); } CertCloseStore(store, 0); } #ifdef DEFAULT_BLACKLIST_FILE ret = gnutls_x509_trust_list_remove_trust_file(list, DEFAULT_BLACKLIST_FILE, GNUTLS_X509_FMT_PEM); if (ret < 0) { _gnutls_debug_log("Could not load blacklist file '%s'\n", DEFAULT_BLACKLIST_FILE); } #endif return r; }
/* This generates p,q params using the B.3.2.2 algorithm in FIPS 186-4. * * The hash function used is SHA384. * The exponent e used is the value in pub->e. */ int _rsa_generate_fips186_4_keypair(struct rsa_public_key *pub, struct rsa_private_key *key, unsigned seed_length, uint8_t * seed, void *progress_ctx, nettle_progress_func * progress, /* Desired size of modulo, in bits */ unsigned n_size) { mpz_t t, r, p1, q1, lcm; int ret; struct dss_params_validation_seeds cert; unsigned l = n_size / 2; FIPS_RULE(n_size == 2048 && seed_length != 14 * 2, 0, "seed length other than 28 bytes\n"); FIPS_RULE(n_size == 3072 && seed_length != 16 * 2, 0, "seed length other than 32 bytes\n"); FIPS_RULE(n_size != 2048 && n_size != 3072, 0, "unsupported size for modulus\n"); if (!mpz_tstbit(pub->e, 0)) { _gnutls_debug_log("Unacceptable e (it is even)\n"); return 0; } if (mpz_cmp_ui(pub->e, 65536) <= 0) { _gnutls_debug_log("Unacceptable e\n"); return 0; } mpz_init(p1); mpz_init(q1); mpz_init(lcm); mpz_init(t); mpz_init(r); mpz_set_ui(t, 1); mpz_mul_2exp(t, t, 256); if (mpz_cmp(pub->e, t) >= 0) { ret = 0; goto cleanup; } cert.pseed_length = sizeof(cert.pseed); ret = rsa_provable_prime(key->p, &cert.pseed_length, cert.pseed, l, seed_length, seed, pub->e, progress_ctx, progress); if (ret == 0) { goto cleanup; } mpz_set_ui(r, 1); mpz_mul_2exp(r, r, (l) - 100); do { cert.qseed_length = sizeof(cert.qseed); ret = rsa_provable_prime(key->q, &cert.qseed_length, cert.qseed, l, cert.pseed_length, cert.pseed, pub->e, progress_ctx, progress); if (ret == 0) { goto cleanup; } cert.pseed_length = cert.qseed_length; memcpy(cert.pseed, cert.qseed, cert.qseed_length); if (mpz_cmp(key->p, key->q) > 0) mpz_sub(t, key->p, key->q); else mpz_sub(t, key->q, key->p); } while (mpz_cmp(t, r) <= 0); memset(&cert, 0, sizeof(cert)); mpz_mul(pub->n, key->p, key->q); if (mpz_sizeinbase(pub->n, 2) != n_size) { ret = 0; goto cleanup; } /* c = q^{-1} (mod p) */ if (mpz_invert(key->c, key->q, key->p) == 0) { ret = 0; goto cleanup; } mpz_sub_ui(p1, key->p, 1); mpz_sub_ui(q1, key->q, 1); mpz_lcm(lcm, p1, q1); if (mpz_invert(key->d, pub->e, lcm) == 0) { ret = 0; goto cleanup; } /* check whether d > 2^(nlen/2) -- FIPS186-4 5.3.1 */ if (mpz_sizeinbase(key->d, 2) < n_size/2) { ret = 0; goto cleanup; } /* Done! Almost, we must compute the auxiliary private values. */ /* a = d % (p-1) */ mpz_fdiv_r(key->a, key->d, p1); /* b = d % (q-1) */ mpz_fdiv_r(key->b, key->d, q1); /* c was computed earlier */ pub->size = key->size = (n_size + 7) / 8; if (pub->size < RSA_MINIMUM_N_OCTETS) { ret = 0; goto cleanup; } ret = 1; cleanup: mpz_clear(p1); mpz_clear(q1); mpz_clear(lcm); mpz_clear(t); mpz_clear(r); return ret; }
/*- * _gnutls_privkey_import_system: * @pkey: The private key * @url: The URL of the key * * This function will import the given private key to the abstract * #gnutls_privkey_t type. * * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a * negative error value. * * Since: 3.4.0 * -*/ int _gnutls_privkey_import_system_url(gnutls_privkey_t pkey, const char *url) { #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP) return gnutls_assert_val(GNUTLS_E_UNIMPLEMENTED_FEATURE); #else uint8_t id[MAX_WID_SIZE]; HCERTSTORE store = NULL; size_t id_size; const CERT_CONTEXT *cert = NULL; CRYPT_HASH_BLOB blob; CRYPT_KEY_PROV_INFO *kpi = NULL; NCRYPT_KEY_HANDLE nc = NULL; HCRYPTPROV hCryptProv = NULL; NCRYPT_PROV_HANDLE sctx = NULL; DWORD kpi_size; SECURITY_STATUS r; int ret, enc_too = 0; WCHAR algo_str[64]; DWORD algo_str_size = 0; priv_st *priv; DWORD i, dwErrCode = 0; if (ncrypt_init == 0) return gnutls_assert_val(GNUTLS_E_UNIMPLEMENTED_FEATURE); if (url == NULL) return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST); priv = gnutls_calloc(1, sizeof(*priv)); if (priv == NULL) return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR); id_size = sizeof(id); ret = get_id(url, id, &id_size, 0); if (ret < 0) return gnutls_assert_val(ret); blob.cbData = id_size; blob.pbData = id; store = CertOpenStore(CERT_STORE_PROV_SYSTEM, 0, 0, CERT_SYSTEM_STORE_CURRENT_USER, L"MY"); if (store == NULL) { gnutls_assert(); ret = GNUTLS_E_FILE_ERROR; goto cleanup; } cert = CertFindCertificateInStore(store, X509_ASN_ENCODING, 0, CERT_FIND_KEY_IDENTIFIER, &blob, NULL); if (cert == NULL) { char buf[64]; _gnutls_debug_log("cannot find ID: %s from %s\n", _gnutls_bin2hex(id, id_size, buf, sizeof(buf), NULL), url); ret = gnutls_assert_val(GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE); goto cleanup; } kpi_size = 0; r = CertGetCertificateContextProperty(cert, CERT_KEY_PROV_INFO_PROP_ID, NULL, &kpi_size); if (r == 0) { _gnutls_debug_log("error in getting context: %d from %s\n", (int)GetLastError(), url); ret = gnutls_assert_val(GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE); goto cleanup; } kpi = gnutls_malloc(kpi_size); if (kpi == NULL) { gnutls_assert(); ret = GNUTLS_E_MEMORY_ERROR; goto cleanup; } r = CertGetCertificateContextProperty(cert, CERT_KEY_PROV_INFO_PROP_ID, kpi, &kpi_size); if (r == 0) { _gnutls_debug_log("error in getting context: %d from %s\n", (int)GetLastError(), url); ret = gnutls_assert_val(GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE); goto cleanup; } r = pNCryptOpenStorageProvider(&sctx, kpi->pwszProvName, 0); if (!FAILED(r)) { /* if this works carry on with CNG */ r = pNCryptOpenKey(sctx, &nc, kpi->pwszContainerName, 0, 0); if (FAILED(r)) { ret = gnutls_assert_val (GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE); goto cleanup; } r = pNCryptGetProperty(nc, NCRYPT_ALGORITHM_PROPERTY, (BYTE *) algo_str, sizeof(algo_str), &algo_str_size, 0); if (FAILED(r)) { ret = gnutls_assert_val (GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE); goto cleanup; } if (StrCmpW(algo_str, BCRYPT_RSA_ALGORITHM) == 0) { priv->pk = GNUTLS_PK_RSA; priv->sign_algo = GNUTLS_SIGN_RSA_SHA256; enc_too = 1; } else if (StrCmpW(algo_str, BCRYPT_DSA_ALGORITHM) == 0) { priv->pk = GNUTLS_PK_DSA; priv->sign_algo = GNUTLS_SIGN_DSA_SHA1; } else if (StrCmpW(algo_str, BCRYPT_ECDSA_P256_ALGORITHM) == 0) { priv->pk = GNUTLS_PK_EC; priv->sign_algo = GNUTLS_SIGN_ECDSA_SHA256; } else if (StrCmpW(algo_str, BCRYPT_ECDSA_P384_ALGORITHM) == 0) { priv->pk = GNUTLS_PK_EC; priv->sign_algo = GNUTLS_SIGN_ECDSA_SHA384; } else if (StrCmpW(algo_str, BCRYPT_ECDSA_P521_ALGORITHM) == 0) { priv->pk = GNUTLS_PK_EC; priv->sign_algo = GNUTLS_SIGN_ECDSA_SHA512; } else { _gnutls_debug_log("unknown key algorithm: %ls\n", algo_str); ret = gnutls_assert_val(GNUTLS_E_UNKNOWN_PK_ALGORITHM); goto cleanup; } priv->nc = nc; ret = gnutls_privkey_import_ext3(pkey, priv, cng_sign, (enc_too != 0) ? cng_decrypt : NULL, cng_deinit, cng_info, 0); if (ret < 0) { gnutls_assert(); goto cleanup; } } else { /* this should be CAPI */ _gnutls_debug_log ("error in opening CNG keystore: %x from %ls\n", (int)r, kpi->pwszProvName); if (CryptAcquireContextW(&hCryptProv, kpi->pwszContainerName, kpi->pwszProvName, kpi->dwProvType, kpi->dwFlags)) { for (i = 0; i < kpi->cProvParam; i++) if (!CryptSetProvParam(hCryptProv, kpi->rgProvParam[i]. dwParam, kpi->rgProvParam[i]. pbData, kpi->rgProvParam[i]. dwFlags)) { dwErrCode = GetLastError(); break; }; } else { dwErrCode = GetLastError(); } if (ERROR_SUCCESS != dwErrCode) { _gnutls_debug_log ("error in getting cryptprov: %d from %s\n", (int)GetLastError(), url); ret = gnutls_assert_val (GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE); goto cleanup; } { BYTE buf[100 + sizeof(PROV_ENUMALGS_EX) * 2]; PROV_ENUMALGS_EX *pAlgo = (PROV_ENUMALGS_EX *) buf; DWORD len = sizeof(buf); if (CryptGetProvParam (hCryptProv, PP_ENUMALGS_EX, buf, &len, CRYPT_FIRST)) { DWORD hash = 0; do { switch (pAlgo->aiAlgid) { case CALG_RSA_SIGN: priv->pk = GNUTLS_PK_RSA; enc_too = 1; break; case CALG_DSS_SIGN: priv->pk = priv->pk == GNUTLS_PK_RSA ? GNUTLS_PK_RSA : GNUTLS_PK_DSA; break; case CALG_SHA1: hash = 1; break; case CALG_SHA_256: hash = 256; break; default: break; } len = sizeof(buf); // reset the buffer size } while (CryptGetProvParam (hCryptProv, PP_ENUMALGS_EX, buf, &len, CRYPT_NEXT)); if (priv->pk == GNUTLS_PK_DSA) priv->sign_algo = GNUTLS_SIGN_DSA_SHA1; else priv->sign_algo = (hash > 1) ? GNUTLS_SIGN_RSA_SHA256 : GNUTLS_SIGN_RSA_SHA1; } } priv->hCryptProv = hCryptProv; priv->dwKeySpec = kpi->dwKeySpec; ret = gnutls_privkey_import_ext3(pkey, priv, capi_sign, (enc_too != 0) ? capi_decrypt : NULL, capi_deinit, capi_info, 0); if (ret < 0) { gnutls_assert(); goto cleanup; } } ret = 0; cleanup: if (ret < 0) { if (nc != 0) pNCryptFreeObject(nc); if (hCryptProv != 0) CryptReleaseContext(hCryptProv, 0); gnutls_free(priv); } if (sctx != 0) pNCryptFreeObject(sctx); gnutls_free(kpi); if (cert != 0) CertFreeCertificateContext(cert); CertCloseStore(store, 0); return ret; #endif }
static int dn_attr_crt_set(set_dn_func f, void *crt, const gnutls_datum_t * name, const gnutls_datum_t * val, unsigned is_raw) { char _oid[MAX_OID_SIZE]; gnutls_datum_t tmp; const char *oid; int ret; unsigned i,j; if (name->size == 0 || val->size == 0) return gnutls_assert_val(GNUTLS_E_PARSING_ERROR); if (c_isdigit(name->data[0]) != 0) { if (name->size >= sizeof(_oid)) return gnutls_assert_val(GNUTLS_E_PARSING_ERROR); memcpy(_oid, name->data, name->size); _oid[name->size] = 0; oid = _oid; if (gnutls_x509_dn_oid_known(oid) == 0 && !is_raw) { _gnutls_debug_log("Unknown OID: '%s'\n", oid); return gnutls_assert_val(GNUTLS_E_PARSING_ERROR); } } else { oid = _gnutls_ldap_string_to_oid((char *) name->data, name->size); } if (oid == NULL) { _gnutls_debug_log("Unknown DN attribute: '%.*s'\n", (int) name->size, name->data); return gnutls_assert_val(GNUTLS_E_PARSING_ERROR); } if (is_raw) { gnutls_datum_t hex = {val->data+1, val->size-1}; ret = gnutls_hex_decode2(&hex, &tmp); if (ret < 0) return gnutls_assert_val(GNUTLS_E_PARSING_ERROR); } else { tmp.size = val->size; tmp.data = gnutls_malloc(tmp.size+1); if (tmp.data == NULL) { return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR); } /* unescape */ for (j=i=0;i<tmp.size;i++) { if (1+j!=val->size && val->data[j] == '\\') { if (val->data[j+1] == ',' || val->data[j+1] == '#' || val->data[j+1] == ' ' || val->data[j+1] == '+' || val->data[j+1] == '"' || val->data[j+1] == '<' || val->data[j+1] == '>' || val->data[j+1] == ';' || val->data[j+1] == '\\' || val->data[j+1] == '=') { tmp.data[i] = val->data[j+1]; j+=2; tmp.size--; } else { ret = gnutls_assert_val(GNUTLS_E_PARSING_ERROR); goto fail; } } else { tmp.data[i] = val->data[j++]; } } tmp.data[tmp.size] = 0; } ret = f(crt, oid, is_raw, tmp.data, tmp.size); if (ret < 0) { gnutls_assert(); goto fail; } ret = 0; fail: gnutls_free(tmp.data); return ret; }
/* in case of DSA puts into data, r,s */ static int _wrap_nettle_pk_sign (gnutls_pk_algorithm_t algo, gnutls_datum_t * signature, const gnutls_datum_t * vdata, const gnutls_pk_params_st * pk_params) { int ret, hash; switch (algo) { case GNUTLS_PK_ECC: /* we do ECDSA */ { ecc_key priv; struct dsa_signature sig; int hash_len; _ecc_params_to_privkey(pk_params, &priv); dsa_signature_init (&sig); hash = _gnutls_dsa_q_to_hash (algo, pk_params, &hash_len); if (hash_len > vdata->size) { gnutls_assert (); _gnutls_debug_log("Security level of algorithm requires hash %s(%d) or better\n", gnutls_mac_get_name(hash), hash_len); hash_len = vdata->size; } ret = ecc_sign_hash(vdata->data, hash_len, &sig, NULL, rnd_func, &priv); if (ret != 0) { gnutls_assert (); ret = GNUTLS_E_PK_SIGN_FAILED; goto ecdsa_fail; } ret = _gnutls_encode_ber_rs (signature, &sig.r, &sig.s); ecdsa_fail: dsa_signature_clear (&sig); _ecc_params_clear( &priv); if (ret < 0) { gnutls_assert (); goto cleanup; } break; } case GNUTLS_PK_DSA: { struct dsa_public_key pub; struct dsa_private_key priv; struct dsa_signature sig; int hash_len; memset(&priv, 0, sizeof(priv)); memset(&pub, 0, sizeof(pub)); _dsa_params_to_pubkey (pk_params, &pub); _dsa_params_to_privkey (pk_params, &priv); dsa_signature_init (&sig); hash = _gnutls_dsa_q_to_hash (algo, pk_params, &hash_len); if (hash_len > vdata->size) { gnutls_assert (); _gnutls_debug_log("Security level of algorithm requires hash %s(%d) or better\n", gnutls_mac_get_name(hash), hash_len); hash_len = vdata->size; } ret = _dsa_sign (&pub, &priv, NULL, rnd_func, hash_len, vdata->data, &sig); if (ret == 0) { gnutls_assert (); ret = GNUTLS_E_PK_SIGN_FAILED; goto dsa_fail; } ret = _gnutls_encode_ber_rs (signature, &sig.r, &sig.s); dsa_fail: dsa_signature_clear (&sig); if (ret < 0) { gnutls_assert (); goto cleanup; } break; } case GNUTLS_PK_RSA: { struct rsa_private_key priv; bigint_t hash, nc, ri; if (_gnutls_mpi_scan_nz (&hash, vdata->data, vdata->size) != 0) { gnutls_assert (); return GNUTLS_E_MPI_SCAN_FAILED; } memset(&priv, 0, sizeof(priv)); _rsa_params_to_privkey (pk_params, &priv); nc = rsa_blind (hash, pk_params->params[1] /*e */ , pk_params->params[0] /*m */ , &ri); _gnutls_mpi_release (&hash); if (nc == NULL) { gnutls_assert (); ret = GNUTLS_E_MEMORY_ERROR; goto rsa_fail; } rsa_compute_root (&priv, TOMPZ (nc), TOMPZ (nc)); rsa_unblind (nc, ri, pk_params->params[0] /*m */ ); ret = _gnutls_mpi_dprint (nc, signature); rsa_fail: _gnutls_mpi_release (&nc); _gnutls_mpi_release (&ri); if (ret < 0) { gnutls_assert (); goto cleanup; } break; } default: gnutls_assert (); ret = GNUTLS_E_INTERNAL_ERROR; goto cleanup; } ret = 0; cleanup: return ret; }
/* Reads the digest information. * we use DER here, although we should use BER. It works fine * anyway. */ static int decode_ber_digest_info (const gnutls_datum_t * info, gnutls_mac_algorithm_t * hash, opaque * digest, int *digest_size) { ASN1_TYPE dinfo = ASN1_TYPE_EMPTY; int result; char str[1024]; int len; if ((result = asn1_create_element (_gnutls_get_gnutls_asn (), "GNUTLS.DigestInfo", &dinfo)) != ASN1_SUCCESS) { gnutls_assert (); return _gnutls_asn2err (result); } result = asn1_der_decoding (&dinfo, info->data, info->size, NULL); if (result != ASN1_SUCCESS) { gnutls_assert (); asn1_delete_structure (&dinfo); return _gnutls_asn2err (result); } len = sizeof (str) - 1; result = asn1_read_value (dinfo, "digestAlgorithm.algorithm", str, &len); if (result != ASN1_SUCCESS) { gnutls_assert (); asn1_delete_structure (&dinfo); return _gnutls_asn2err (result); } *hash = _gnutls_x509_oid2mac_algorithm (str); if (*hash == GNUTLS_MAC_UNKNOWN) { _gnutls_debug_log ("verify.c: HASH OID: %s\n", str); gnutls_assert (); asn1_delete_structure (&dinfo); return GNUTLS_E_UNKNOWN_ALGORITHM; } len = sizeof (str) - 1; result = asn1_read_value (dinfo, "digestAlgorithm.parameters", str, &len); /* To avoid permitting garbage in the parameters field, either the parameters field is not present, or it contains 0x05 0x00. */ if (!(result == ASN1_ELEMENT_NOT_FOUND || (result == ASN1_SUCCESS && len == ASN1_NULL_SIZE && memcmp (str, ASN1_NULL, ASN1_NULL_SIZE) == 0))) { gnutls_assert (); asn1_delete_structure (&dinfo); return GNUTLS_E_ASN1_GENERIC_ERROR; } result = asn1_read_value (dinfo, "digest", digest, digest_size); if (result != ASN1_SUCCESS) { gnutls_assert (); asn1_delete_structure (&dinfo); return _gnutls_asn2err (result); } asn1_delete_structure (&dinfo); return 0; }
/** * gnutls_store_pubkey: * @db_name: A file specifying the stored keys (use NULL for the default) * @tdb: A storage structure or NULL to use the default * @host: The peer's name * @service: non-NULL if this key is specific to a service (e.g. http) * @cert_type: The type of the certificate * @cert: The data of the certificate * @expiration: The expiration time (use 0 to disable expiration) * @flags: should be 0. * * This function will store a raw public-key or a public-key provided via * a raw (DER-encoded) certificate to the list of stored public keys. The key * will be considered valid until the provided expiration time. * * The @tdb variable if non-null specifies a custom backend for * the storage of entries. If it is NULL then the * default file backend will be used. * * Unless an alternative @tdb is provided, the storage format is a textual format * consisting of a line for each host with fields separated by '|'. The contents of * the fields are a format-identifier which is set to 'g0', the hostname that the * rest of the data applies to, the numeric port or host name, the expiration * time in seconds since the epoch (0 for no expiration), and a base64 * encoding of the raw (DER) public key information (SPKI) of the peer. * * As of GnuTLS 3.6.6 this function also accepts raw public keys. * * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a * negative error value. * * Since: 3.0.13 **/ int gnutls_store_pubkey(const char *db_name, gnutls_tdb_t tdb, const char *host, const char *service, gnutls_certificate_type_t cert_type, const gnutls_datum_t * cert, time_t expiration, unsigned int flags) { gnutls_datum_t pubkey = { NULL, 0 }; // Holds the pubkey in subjectPublicKeyInfo format (DER encoded) int ret; char local_file[MAX_FILENAME]; bool need_free; if (db_name == NULL && tdb == NULL) { ret = _gnutls_find_config_path(local_file, sizeof(local_file)); if (ret < 0) return gnutls_assert_val(ret); _gnutls_debug_log("Configuration path: %s\n", local_file); mkdir(local_file, 0700); ret = find_config_file(local_file, sizeof(local_file)); if (ret < 0) return gnutls_assert_val(ret); db_name = local_file; } if (tdb == NULL) tdb = &default_tdb; /* Import the public key depending on the provided certificate type */ switch (cert_type) { case GNUTLS_CRT_X509: /* Extract the pubkey from the cert. This function does a malloc * deep down the call chain. We are responsible for freeing. */ ret = _gnutls_x509_raw_crt_to_raw_pubkey(cert, &pubkey); if (ret < 0) { _gnutls_free_datum(&pubkey); return gnutls_assert_val(ret); } need_free = true; break; case GNUTLS_CRT_RAWPK: pubkey.data = cert->data; pubkey.size = cert->size; need_free = false; break; default: return gnutls_assert_val(GNUTLS_E_UNSUPPORTED_CERTIFICATE_TYPE); } _gnutls_debug_log("Configuration file: %s\n", db_name); tdb->store(db_name, host, service, expiration, &pubkey); if (need_free) { _gnutls_free_datum(&pubkey); } return GNUTLS_E_SUCCESS; }
/** * gnutls_pkcs11_privkey_import_url: * @pkey: The structure to store the parsed key * @url: a PKCS 11 url identifying the key * @flags: sequence of GNUTLS_PKCS_PRIVKEY_* * * This function will "import" a PKCS 11 URL identifying a private * key to the #gnutls_pkcs11_privkey_t structure. In reality since * in most cases keys cannot be exported, the private key structure * is being associated with the available operations on the token. * * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a * negative error value. **/ int gnutls_pkcs11_privkey_import_url (gnutls_pkcs11_privkey_t pkey, const char *url, unsigned int flags) { int ret; struct ck_function_list *module; struct ck_attribute *attr; ck_session_handle_t pks; ck_object_handle_t obj; struct ck_attribute a[4]; ck_key_type_t key_type; ret = pkcs11_url_to_info (url, &pkey->info); if (ret < 0) { gnutls_assert (); return ret; } pkey->flags = flags; attr = p11_kit_uri_get_attribute (pkey->info, CKA_CLASS); if (!attr || attr->value_len != sizeof (ck_object_class_t) || *(ck_object_class_t*)attr->value != CKO_PRIVATE_KEY) { gnutls_assert (); return GNUTLS_E_INVALID_REQUEST; } attr = p11_kit_uri_get_attribute (pkey->info, CKA_ID); if (!attr || !attr->value_len) { attr = p11_kit_uri_get_attribute (pkey->info, CKA_LABEL); if (!attr || !attr->value_len) { gnutls_assert (); return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE; } } FIND_OBJECT (module, pks, obj, pkey); a[0].type = CKA_KEY_TYPE; a[0].value = &key_type; a[0].value_len = sizeof (key_type); if (pkcs11_get_attribute_value (module, pks, obj, a, 1) == CKR_OK) { pkey->pk_algorithm = mech_to_pk(key_type); if (pkey->pk_algorithm == GNUTLS_PK_UNKNOWN) { _gnutls_debug_log("Cannot determine PKCS #11 key algorithm\n"); ret = GNUTLS_E_UNKNOWN_ALGORITHM; goto cleanup; } } ret = 0; cleanup: pkcs11_close_session (module, pks); return ret; }
static int do_device_source_urandom (int init) { time_t now = gnutls_time (NULL); int read_size = DEVICE_READ_SIZE; if (init) { int old; device_fd = open ("/dev/urandom", O_RDONLY); if (device_fd < 0) { _gnutls_debug_log ("Cannot open urandom!\n"); return GNUTLS_E_FILE_ERROR; } old = fcntl (device_fd, F_GETFD); fcntl (device_fd, F_SETFD, old | 1); device_last_read = now; read_size = DEVICE_READ_SIZE_MAX; /* initially read more data */ } if ((device_fd > 0) && (init || ((now - device_last_read) > DEVICE_READ_INTERVAL))) { /* More than a minute since we last read the device */ uint8_t buf[DEVICE_READ_SIZE_MAX]; uint32_t done; for (done = 0; done < read_size;) { int res; do res = read (device_fd, buf + done, sizeof (buf) - done); while (res < 0 && errno == EINTR); if (res <= 0) { if (res < 0) { _gnutls_debug_log ("Failed to read /dev/urandom: %s\n", strerror (errno)); } else { _gnutls_debug_log ("Failed to read /dev/urandom: end of file\n"); } return GNUTLS_E_INTERNAL_ERROR; } done += res; } device_last_read = now; return yarrow256_update (&yctx, RANDOM_SOURCE_DEVICE, read_size * 8 / 2 /* we trust the RNG */ , read_size, buf); } return 0; }
/* Decodes the SafeContents, and puts the output in * the given bag. */ int _pkcs12_decode_safe_contents(const gnutls_datum_t * content, gnutls_pkcs12_bag_t bag) { char oid[MAX_OID_SIZE], root[ASN1_MAX_NAME_SIZE]; ASN1_TYPE c2 = ASN1_TYPE_EMPTY; int len, result; int bag_type; gnutls_datum_t attr_val; gnutls_datum_t t; int count = 0, i, attributes, j; /* Step 1. Extract the SEQUENCE. */ if ((result = asn1_create_element (_gnutls_get_pkix(), "PKIX1.pkcs-12-SafeContents", &c2)) != ASN1_SUCCESS) { gnutls_assert(); result = _gnutls_asn2err(result); goto cleanup; } result = asn1_der_decoding(&c2, content->data, content->size, NULL); if (result != ASN1_SUCCESS) { gnutls_assert(); result = _gnutls_asn2err(result); goto cleanup; } /* Count the number of bags */ result = asn1_number_of_elements(c2, "", &count); if (result != ASN1_SUCCESS) { gnutls_assert(); result = _gnutls_asn2err(result); goto cleanup; } bag->bag_elements = MIN(MAX_BAG_ELEMENTS, count); for (i = 0; i < bag->bag_elements; i++) { snprintf(root, sizeof(root), "?%u.bagId", i + 1); len = sizeof(oid); result = asn1_read_value(c2, root, oid, &len); if (result != ASN1_SUCCESS) { gnutls_assert(); result = _gnutls_asn2err(result); goto cleanup; } /* Read the Bag type */ bag_type = oid2bag(oid); if (bag_type < 0) { gnutls_assert(); goto cleanup; } /* Read the Bag Value */ snprintf(root, sizeof(root), "?%u.bagValue", i + 1); result = _gnutls_x509_read_value(c2, root, &bag->element[i].data); if (result < 0) { gnutls_assert(); goto cleanup; } if (bag_type == GNUTLS_BAG_CERTIFICATE || bag_type == GNUTLS_BAG_CRL || bag_type == GNUTLS_BAG_SECRET) { gnutls_datum_t tmp = bag->element[i].data; result = _pkcs12_decode_crt_bag(bag_type, &tmp, &bag->element[i].data); if (result < 0) { gnutls_assert(); goto cleanup; } _gnutls_free_datum(&tmp); } /* read the bag attributes */ snprintf(root, sizeof(root), "?%u.bagAttributes", i + 1); result = asn1_number_of_elements(c2, root, &attributes); if (result != ASN1_SUCCESS && result != ASN1_ELEMENT_NOT_FOUND) { gnutls_assert(); result = _gnutls_asn2err(result); goto cleanup; } if (attributes < 0) attributes = 1; if (result != ASN1_ELEMENT_NOT_FOUND) for (j = 0; j < attributes; j++) { snprintf(root, sizeof(root), "?%u.bagAttributes.?%u", i + 1, j + 1); result = _gnutls_x509_decode_and_read_attribute (c2, root, oid, sizeof(oid), &attr_val, 1, 0); if (result < 0) { gnutls_assert(); continue; /* continue in case we find some known attributes */ } if (strcmp(oid, KEY_ID_OID) == 0) { result = _gnutls_x509_decode_string (ASN1_ETYPE_OCTET_STRING, attr_val.data, attr_val.size, &t); _gnutls_free_datum(&attr_val); if (result < 0) { gnutls_assert(); _gnutls_debug_log ("Error decoding PKCS12 Bag Attribute OID '%s'\n", oid); continue; } attr_val.data = t.data; attr_val.size = t.size; bag->element[i].local_key_id = attr_val; } else if (strcmp(oid, FRIENDLY_NAME_OID) == 0) { result = _gnutls_x509_decode_string (ASN1_ETYPE_BMP_STRING, attr_val.data, attr_val.size, &t); _gnutls_free_datum(&attr_val); if (result < 0) { gnutls_assert(); _gnutls_debug_log ("Error decoding PKCS12 Bag Attribute OID '%s'\n", oid); continue; } attr_val.data = t.data; attr_val.size = t.size; bag->element[i].friendly_name = (char *) t.data; } else { _gnutls_free_datum(&attr_val); _gnutls_debug_log ("Unknown PKCS12 Bag Attribute OID '%s'\n", oid); } } bag->element[i].type = bag_type; } asn1_delete_structure(&c2); return 0; cleanup: if (c2) asn1_delete_structure(&c2); return result; }
int _gnutls_compress (comp_hd_t handle, const opaque * plain, size_t plain_size, opaque ** compressed, size_t max_comp_size) { int compressed_size = GNUTLS_E_COMPRESSION_FAILED; int err; /* NULL compression is not handled here */ if (handle == NULL) { gnutls_assert (); return GNUTLS_E_INTERNAL_ERROR; } switch (handle->algo) { #ifdef USE_LZO case GNUTLS_COMP_LZO: { lzo_uint out_len; size_t size; if (_gnutls_lzo1x_1_compress == NULL) return GNUTLS_E_COMPRESSION_FAILED; size = plain_size + plain_size / 64 + 16 + 3; *compressed = gnutls_malloc (size); if (*compressed == NULL) { gnutls_assert (); return GNUTLS_E_MEMORY_ERROR; } err = _gnutls_lzo1x_1_compress (plain, plain_size, *compressed, &out_len, handle->handle); if (err != LZO_E_OK) { gnutls_assert (); gnutls_free (*compressed); *compressed = NULL; return GNUTLS_E_COMPRESSION_FAILED; } compressed_size = out_len; break; } #endif #ifdef HAVE_LIBZ case GNUTLS_COMP_DEFLATE: { uLongf size; z_stream *zhandle; size = (plain_size + plain_size) + 10; *compressed = gnutls_malloc (size); if (*compressed == NULL) { gnutls_assert (); return GNUTLS_E_MEMORY_ERROR; } zhandle = handle->handle; zhandle->next_in = (Bytef *) plain; zhandle->avail_in = plain_size; zhandle->next_out = (Bytef *) * compressed; zhandle->avail_out = size; err = deflate (zhandle, Z_SYNC_FLUSH); if (err != Z_OK || zhandle->avail_in != 0) { gnutls_assert (); gnutls_free (*compressed); *compressed = NULL; return GNUTLS_E_COMPRESSION_FAILED; } compressed_size = size - zhandle->avail_out; break; } #endif default: gnutls_assert (); return GNUTLS_E_INTERNAL_ERROR; } /* switch */ #ifdef COMPRESSION_DEBUG _gnutls_debug_log ("Compression ratio: %f\n", (float) ((float) compressed_size / (float) plain_size)); #endif if ((size_t) compressed_size > max_comp_size) { gnutls_free (*compressed); *compressed = NULL; return GNUTLS_E_COMPRESSION_FAILED; } return compressed_size; }
/** * gnutls_global_init: * * This function performs any required precalculations, detects * the supported CPU capabilities and initializes the underlying * cryptographic backend. In order to free any resources * taken by this call you should gnutls_global_deinit() * when gnutls usage is no longer needed. * * This function increments a global counter, so that * gnutls_global_deinit() only releases resources when it has been * called as many times as gnutls_global_init(). This is useful when * GnuTLS is used by more than one library in an application. This * function can be called many times, but will only do something the * first time. * * Note! This function is not thread safe. If two threads call this * function simultaneously, they can cause a race between checking * the global counter and incrementing it, causing both threads to * execute the library initialization code. That would lead to a * memory leak. To handle this, your application could invoke this * function after aquiring a thread mutex. To ignore the potential * memory leak is also an option. * * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, * otherwise a negative error code is returned. **/ int gnutls_global_init (void) { int result = 0; int res; if (_gnutls_init++) goto out; if (gl_sockets_startup (SOCKETS_1_1)) return gnutls_assert_val(GNUTLS_E_FILE_ERROR); bindtextdomain (PACKAGE, LOCALEDIR); res = gnutls_crypto_init (); if (res != 0) { gnutls_assert (); return GNUTLS_E_CRYPTO_INIT_FAILED; } _gnutls_register_accel_crypto(); /* initialize ASN.1 parser * This should not deal with files in the final * version. */ if (asn1_check_version (GNUTLS_MIN_LIBTASN1_VERSION) == NULL) { gnutls_assert (); _gnutls_debug_log ("Checking for libtasn1 failed: %s < %s\n", asn1_check_version (NULL), GNUTLS_MIN_LIBTASN1_VERSION); return GNUTLS_E_INCOMPATIBLE_LIBTASN1_LIBRARY; } res = asn1_array2tree (pkix_asn1_tab, &_gnutls_pkix1_asn, NULL); if (res != ASN1_SUCCESS) { result = _gnutls_asn2err (res); goto out; } res = asn1_array2tree (gnutls_asn1_tab, &_gnutls_gnutls_asn, NULL); if (res != ASN1_SUCCESS) { result = _gnutls_asn2err (res); goto out; } /* Initialize the random generator */ result = _gnutls_rnd_init (); if (result < 0) { gnutls_assert (); goto out; } /* Initialize the default TLS extensions */ result = _gnutls_ext_init (); if (result < 0) { gnutls_assert (); goto out; } result = gnutls_mutex_init(&_gnutls_file_mutex); if (result < 0) { gnutls_assert(); goto out; } result = gnutls_system_global_init (); if (result < 0) { gnutls_assert (); goto out; } #ifdef ENABLE_PKCS11 gnutls_pkcs11_init (GNUTLS_PKCS11_FLAG_AUTO, NULL); #endif _gnutls_cryptodev_init (); out: return result; }
/* returns data_size or a negative number on failure */ static int _gnutls_server_name_send_params(gnutls_session_t session, gnutls_buffer_st * extdata) { uint16_t len; unsigned i; int total_size = 0, ret; server_name_ext_st *priv; extension_priv_data_t epriv; ret = _gnutls_ext_get_session_data(session, GNUTLS_EXTENSION_SERVER_NAME, &epriv); if (ret < 0) return 0; /* this function sends the client extension data (dnsname) */ if (session->security_parameters.entity == GNUTLS_CLIENT) { priv = epriv; if (priv->server_names_size == 0) return 0; /* uint16_t */ total_size = 2; for (i = 0; i < priv->server_names_size; i++) { /* count the total size */ len = priv->server_names[i].name_length; /* uint8_t + uint16_t + size */ total_size += 1 + 2 + len; } /* UINT16: write total size of all names */ ret = _gnutls_buffer_append_prefix(extdata, 16, total_size - 2); if (ret < 0) return gnutls_assert_val(ret); for (i = 0; i < priv->server_names_size; i++) { switch (priv->server_names[i].type) { case GNUTLS_NAME_DNS: len = priv->server_names[i].name_length; if (len == 0) break; /* UINT8: type of this extension * UINT16: size of the first name * LEN: the actual server name. */ ret = _gnutls_buffer_append_prefix(extdata, 8, 0); if (ret < 0) return gnutls_assert_val(ret); _gnutls_debug_log("HSK[%p]: sent server name: '%s'\n", session, priv->server_names[i].name); ret = _gnutls_buffer_append_data_prefix (extdata, 16, priv->server_names[i].name, len); if (ret < 0) return gnutls_assert_val(ret); break; default: gnutls_assert(); return GNUTLS_E_INTERNAL_ERROR; } } } return total_size; }
/** * gnutls_openpgp_keyring_import: * @keyring: The structure to store the parsed key. * @data: The RAW or BASE64 encoded keyring. * @format: One of #gnutls_openpgp_keyring_fmt elements. * * This function will convert the given RAW or Base64 encoded keyring * to the native #gnutls_openpgp_keyring_t format. The output will be * stored in 'keyring'. * * Returns: %GNUTLS_E_SUCCESS on success, or an error code. **/ int gnutls_openpgp_keyring_import (gnutls_openpgp_keyring_t keyring, const gnutls_datum_t * data, gnutls_openpgp_crt_fmt_t format) { cdk_error_t err; cdk_stream_t input = NULL; size_t raw_len = 0; uint8_t *raw_data = NULL; if (data->data == NULL || data->size == 0) { gnutls_assert (); return GNUTLS_E_OPENPGP_GETKEY_FAILED; } _gnutls_debug_log ("PGP: keyring import format '%s'\n", format == GNUTLS_OPENPGP_FMT_RAW ? "raw" : "base64"); /* Create a new stream from the given data, decode it, and import * the raw database. This to avoid using opencdk streams which are * not thread safe. */ if (format == GNUTLS_OPENPGP_FMT_BASE64) { size_t written = 0; err = cdk_stream_tmp_from_mem (data->data, data->size, &input); if (err == 0) err = cdk_stream_set_armor_flag (input, 0); if (err) { gnutls_assert (); err = _gnutls_map_cdk_rc (err); goto error; } raw_len = cdk_stream_get_length (input); if (raw_len == 0) { gnutls_assert (); err = GNUTLS_E_BASE64_DECODING_ERROR; goto error; } raw_data = gnutls_malloc (raw_len); if (raw_data == NULL) { gnutls_assert (); err = GNUTLS_E_MEMORY_ERROR; goto error; } do { err = cdk_stream_read (input, raw_data + written, raw_len - written); if (err > 0) written += err; } while (written < raw_len && err != EOF && err > 0); raw_len = written; } else { /* RAW */ raw_len = data->size; raw_data = data->data; } err = cdk_keydb_new_from_mem (&keyring->db, 0, 0, raw_data, raw_len); if (err) gnutls_assert (); return _gnutls_map_cdk_rc (err); error: gnutls_free (raw_data); cdk_stream_close (input); return err; }
/* Writes the digest information and the digest in a DER encoded * structure. The digest info is allocated and stored into the info structure. */ int encode_ber_digest_info(const mac_entry_st * e, const gnutls_datum_t * digest, gnutls_datum_t * output) { ASN1_TYPE dinfo = ASN1_TYPE_EMPTY; int result; const char *algo; uint8_t *tmp_output; int tmp_output_size; algo = _gnutls_x509_mac_to_oid(e); if (algo == NULL) { gnutls_assert(); _gnutls_debug_log("Hash algorithm: %d has no OID\n", e->id); return GNUTLS_E_UNKNOWN_PK_ALGORITHM; } if ((result = asn1_create_element(_gnutls_get_gnutls_asn(), "GNUTLS.DigestInfo", &dinfo)) != ASN1_SUCCESS) { gnutls_assert(); return _gnutls_asn2err(result); } result = asn1_write_value(dinfo, "digestAlgorithm.algorithm", algo, 1); if (result != ASN1_SUCCESS) { gnutls_assert(); asn1_delete_structure(&dinfo); return _gnutls_asn2err(result); } /* Write an ASN.1 NULL in the parameters field. This matches RFC 3279 and RFC 4055, although is arguable incorrect from a historic perspective (see those documents for more information). Regardless of what is correct, this appears to be what most implementations do. */ result = asn1_write_value(dinfo, "digestAlgorithm.parameters", ASN1_NULL, ASN1_NULL_SIZE); if (result != ASN1_SUCCESS) { gnutls_assert(); asn1_delete_structure(&dinfo); return _gnutls_asn2err(result); } result = asn1_write_value(dinfo, "digest", digest->data, digest->size); if (result != ASN1_SUCCESS) { gnutls_assert(); asn1_delete_structure(&dinfo); return _gnutls_asn2err(result); } tmp_output_size = 0; result = asn1_der_coding(dinfo, "", NULL, &tmp_output_size, NULL); if (result != ASN1_MEM_ERROR) { gnutls_assert(); asn1_delete_structure(&dinfo); return _gnutls_asn2err(result); } tmp_output = gnutls_malloc(tmp_output_size); if (tmp_output == NULL) { gnutls_assert(); asn1_delete_structure(&dinfo); return GNUTLS_E_MEMORY_ERROR; } result = asn1_der_coding(dinfo, "", tmp_output, &tmp_output_size, NULL); if (result != ASN1_SUCCESS) { gnutls_assert(); asn1_delete_structure(&dinfo); return _gnutls_asn2err(result); } asn1_delete_structure(&dinfo); output->size = tmp_output_size; output->data = tmp_output; return 0; }
/** * gnutls_x509_trust_list_add_crls: * @list: The list * @crl_list: A list of CRLs * @crl_size: The length of the CRL list * @flags: flags from %gnutls_trust_list_flags_t * @verification_flags: gnutls_certificate_verify_flags if flags specifies GNUTLS_TL_VERIFY_CRL * * This function will add the given certificate revocation lists * to the trusted list. The CRLs in @crl_list must not be deinitialized * during the lifetime of @list. * * This function must be called after gnutls_x509_trust_list_add_cas() * to allow verifying the CRLs for validity. If the flag %GNUTLS_TL_NO_DUPLICATES * is given, then the final CRL list will not contain duplicate entries. * * If the flag %GNUTLS_TL_NO_DUPLICATES is given, gnutls_x509_trust_list_deinit() must be * called with parameter @all being 1. * * If flag %GNUTLS_TL_VERIFY_CRL is given the CRLs will be verified before being added, * and if verification fails, they will be skipped. * * Returns: The number of added elements is returned; that includes * duplicate entries. * * Since: 3.0 **/ int gnutls_x509_trust_list_add_crls(gnutls_x509_trust_list_t list, const gnutls_x509_crl_t * crl_list, unsigned crl_size, unsigned int flags, unsigned int verification_flags) { int ret; unsigned x, i, j = 0; unsigned int vret = 0; uint32_t hash; gnutls_x509_crl_t *tmp; /* Probably we can optimize things such as removing duplicates * etc. */ if (crl_size == 0 || crl_list == NULL) return 0; for (i = 0; i < crl_size; i++) { hash = hash_pjw_bare(crl_list[i]->raw_issuer_dn.data, crl_list[i]->raw_issuer_dn.size); hash %= list->size; if (flags & GNUTLS_TL_VERIFY_CRL) { ret = gnutls_x509_crl_verify(crl_list[i], list->node[hash]. trusted_cas, list->node[hash]. trusted_ca_size, verification_flags, &vret); if (ret < 0 || vret != 0) { _gnutls_debug_log("CRL verification failed, not adding it\n"); if (flags & GNUTLS_TL_NO_DUPLICATES) gnutls_x509_crl_deinit(crl_list[i]); if (flags & GNUTLS_TL_FAIL_ON_INVALID_CRL) return gnutls_assert_val(GNUTLS_E_CRL_VERIFICATION_ERROR); continue; } } /* If the CRL added overrides a previous one, then overwrite * the old one */ if (flags & GNUTLS_TL_NO_DUPLICATES) { for (x=0;x<list->node[hash].crl_size;x++) { if (crl_list[i]->raw_issuer_dn.size == list->node[hash].crls[x]->raw_issuer_dn.size && memcmp(crl_list[i]->raw_issuer_dn.data, list->node[hash].crls[x]->raw_issuer_dn.data, crl_list[i]->raw_issuer_dn.size) == 0) { if (gnutls_x509_crl_get_this_update(crl_list[i]) >= gnutls_x509_crl_get_this_update(list->node[hash].crls[x])) { gnutls_x509_crl_deinit(list->node[hash].crls[x]); list->node[hash].crls[x] = crl_list[i]; goto next; } else { /* The new is older, discard it */ gnutls_x509_crl_deinit(crl_list[i]); goto next; } } } } tmp = gnutls_realloc(list->node[hash].crls, (list->node[hash].crl_size + 1) * sizeof(list->node[hash]. crls[0])); if (tmp == NULL) { ret = i; gnutls_assert(); if (flags & GNUTLS_TL_NO_DUPLICATES) while (i < crl_size) gnutls_x509_crl_deinit(crl_list[i++]); return ret; } list->node[hash].crls = tmp; list->node[hash].crls[list->node[hash].crl_size] = crl_list[i]; list->node[hash].crl_size++; next: j++; } return j; }
/* Copies a gnutls_openpgp_privkey_t to a gnutls_privkey structure. */ int _gnutls_openpgp_privkey_to_gkey (gnutls_privkey * dest, gnutls_openpgp_privkey_t src) { int ret = 0; gnutls_openpgp_keyid_t keyid; char err_buf[33]; if (dest == NULL || src == NULL) { gnutls_assert (); return GNUTLS_E_CERTIFICATE_ERROR; } dest->params_size = MAX_PRIV_PARAMS_SIZE; ret = gnutls_openpgp_privkey_get_preferred_key_id (src, keyid); if (ret == 0) { int idx; uint32_t kid32[2]; _gnutls_debug_log ("Importing Openpgp key and using openpgp sub key: %s\n", _gnutls_bin2hex (keyid, sizeof (keyid), err_buf, sizeof (err_buf))); KEYID_IMPORT (kid32, keyid); idx = gnutls_openpgp_privkey_get_subkey_idx (src, keyid); if (idx < 0) { gnutls_assert (); return idx; } dest->pk_algorithm = gnutls_openpgp_privkey_get_subkey_pk_algorithm (src, idx, NULL); ret = _gnutls_openpgp_privkey_get_mpis (src, kid32, dest->params, &dest->params_size); } else { _gnutls_debug_log ("Importing Openpgp key and using main openpgp key.\n"); dest->pk_algorithm = gnutls_openpgp_privkey_get_pk_algorithm (src, NULL); ret = _gnutls_openpgp_privkey_get_mpis (src, NULL, dest->params, &dest->params_size); } if (ret < 0) { gnutls_assert (); return ret; } return 0; }