/* verifies if the certificate is properly signed. * returns GNUTLS_E_PK_VERIFY_SIG_FAILED on failure and 1 on success. * * 'data' is the signed data * 'signature' is the signature! */ int _gnutls_x509_verify_data (gnutls_digest_algorithm_t algo, const gnutls_datum_t * data, const gnutls_datum_t * signature, gnutls_x509_crt_t issuer) { gnutls_pk_params_st issuer_params; int ret; /* Read the MPI parameters from the issuer's certificate. */ ret = _gnutls_x509_crt_get_mpis (issuer, &issuer_params); if (ret < 0) { gnutls_assert (); return ret; } ret = pubkey_verify_data (gnutls_x509_crt_get_pk_algorithm (issuer, NULL), algo, data, signature, &issuer_params); if (ret < 0) { gnutls_assert (); } /* release all allocated MPIs */ gnutls_pk_params_release(&issuer_params); return ret; }
/* verifies if the certificate is properly signed. * returns GNUTLS_E_PK_VERIFY_SIG_FAILED on failure and 1 on success. * * 'tbs' is the signed data * 'signature' is the signature! */ int _gnutls_x509_verify_signature (const gnutls_datum_t * tbs, const gnutls_datum_t * hash, const gnutls_datum_t * signature, gnutls_x509_crt_t issuer) { bigint_t issuer_params[MAX_PUBLIC_PARAMS_SIZE]; int ret, issuer_params_size, i; /* Read the MPI parameters from the issuer's certificate. */ issuer_params_size = MAX_PUBLIC_PARAMS_SIZE; ret = _gnutls_x509_crt_get_mpis (issuer, issuer_params, &issuer_params_size); if (ret < 0) { gnutls_assert (); return ret; } ret = pubkey_verify_sig (tbs, hash, signature, gnutls_x509_crt_get_pk_algorithm (issuer, NULL), issuer_params, issuer_params_size); if (ret < 0) { gnutls_assert (); } /* release all allocated MPIs */ for (i = 0; i < issuer_params_size; i++) { _gnutls_mpi_release (&issuer_params[i]); } return ret; }
/** * gnutls_pubkey_import_x509: * @key: The public key * @crt: The certificate to be imported * @flags: should be zero * * This function will import the given public key to the abstract * #gnutls_pubkey_t type. * * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a * negative error value. * * Since: 2.12.0 **/ int gnutls_pubkey_import_x509(gnutls_pubkey_t key, gnutls_x509_crt_t crt, unsigned int flags) { int ret; gnutls_pk_params_release(&key->params); /* params initialized in _gnutls_x509_crt_get_mpis */ key->pk_algorithm = gnutls_x509_crt_get_pk_algorithm(crt, &key->bits); ret = gnutls_x509_crt_get_key_usage(crt, &key->key_usage, NULL); if (ret < 0) key->key_usage = 0; ret = _gnutls_x509_crt_get_mpis(crt, &key->params); if (ret < 0) { gnutls_assert(); return ret; } return 0; }
/* Checks whether the provided certificates are acceptable * according to verification profile specified. * * @crt: a certificate * @issuer: the certificates issuer (allowed to be NULL) * @sigalg: the signature algorithm used * @flags: the specified verification flags */ static unsigned is_level_acceptable( gnutls_x509_crt_t crt, gnutls_x509_crt_t issuer, gnutls_sign_algorithm_t sigalg, unsigned flags) { gnutls_certificate_verification_profiles_t profile = GNUTLS_VFLAGS_TO_PROFILE(flags); const mac_entry_st *entry; int issuer_pkalg = 0, pkalg, ret; unsigned bits = 0, issuer_bits = 0, sym_bits = 0; gnutls_pk_params_st params; gnutls_sec_param_t sp; int hash; if (profile == 0) return 1; pkalg = gnutls_x509_crt_get_pk_algorithm(crt, &bits); if (pkalg < 0) return gnutls_assert_val(0); if (issuer) { issuer_pkalg = gnutls_x509_crt_get_pk_algorithm(issuer, &issuer_bits); if (issuer_pkalg < 0) return gnutls_assert_val(0); } switch (profile) { CASE_SEC_PARAM(GNUTLS_PROFILE_VERY_WEAK, GNUTLS_SEC_PARAM_VERY_WEAK); CASE_SEC_PARAM(GNUTLS_PROFILE_LOW, GNUTLS_SEC_PARAM_LOW); CASE_SEC_PARAM(GNUTLS_PROFILE_LEGACY, GNUTLS_SEC_PARAM_LEGACY); CASE_SEC_PARAM(GNUTLS_PROFILE_MEDIUM, GNUTLS_SEC_PARAM_MEDIUM); CASE_SEC_PARAM(GNUTLS_PROFILE_HIGH, GNUTLS_SEC_PARAM_HIGH); CASE_SEC_PARAM(GNUTLS_PROFILE_ULTRA, GNUTLS_SEC_PARAM_ULTRA); case GNUTLS_PROFILE_SUITEB128: case GNUTLS_PROFILE_SUITEB192: { unsigned curve, issuer_curve; /* check suiteB params validity: rfc5759 */ if (gnutls_x509_crt_get_version(crt) != 3) { _gnutls_debug_log("SUITEB: certificate uses an unacceptable version number\n"); return gnutls_assert_val(0); } if (sigalg != GNUTLS_SIGN_ECDSA_SHA256 && sigalg != GNUTLS_SIGN_ECDSA_SHA384) { _gnutls_debug_log("SUITEB: certificate is not signed using ECDSA-SHA256 or ECDSA-SHA384\n"); return gnutls_assert_val(0); } if (pkalg != GNUTLS_PK_EC) { _gnutls_debug_log("SUITEB: certificate does not contain ECC parameters\n"); return gnutls_assert_val(0); } if (issuer_pkalg != GNUTLS_PK_EC) { _gnutls_debug_log("SUITEB: certificate's issuer does not have ECC parameters\n"); return gnutls_assert_val(0); } ret = _gnutls_x509_crt_get_mpis(crt, ¶ms); if (ret < 0) { _gnutls_debug_log("SUITEB: cannot read certificate params\n"); return gnutls_assert_val(0); } curve = params.flags; gnutls_pk_params_release(¶ms); if (curve != GNUTLS_ECC_CURVE_SECP256R1 && curve != GNUTLS_ECC_CURVE_SECP384R1) { _gnutls_debug_log("SUITEB: certificate's ECC params do not contain SECP256R1 or SECP384R1\n"); return gnutls_assert_val(0); } if (profile == GNUTLS_PROFILE_SUITEB192) { if (curve != GNUTLS_ECC_CURVE_SECP384R1) { _gnutls_debug_log("SUITEB192: certificate does not use SECP384R1\n"); return gnutls_assert_val(0); } } if (issuer != NULL) { if (gnutls_x509_crt_get_version(issuer) != 3) { _gnutls_debug_log("SUITEB: certificate's issuer uses an unacceptable version number\n"); return gnutls_assert_val(0); } ret = _gnutls_x509_crt_get_mpis(issuer, ¶ms); if (ret < 0) { _gnutls_debug_log("SUITEB: cannot read certificate params\n"); return gnutls_assert_val(0); } issuer_curve = params.flags; gnutls_pk_params_release(¶ms); if (issuer_curve != GNUTLS_ECC_CURVE_SECP256R1 && issuer_curve != GNUTLS_ECC_CURVE_SECP384R1) { _gnutls_debug_log("SUITEB: certificate's issuer ECC params do not contain SECP256R1 or SECP384R1\n"); return gnutls_assert_val(0); } if (issuer_curve < curve) { _gnutls_debug_log("SUITEB: certificate's issuer ECC params are weaker than the certificate's\n"); return gnutls_assert_val(0); } if (sigalg == GNUTLS_SIGN_ECDSA_SHA256 && issuer_curve == GNUTLS_ECC_CURVE_SECP384R1) { _gnutls_debug_log("SUITEB: certificate is signed with ECDSA-SHA256 when using SECP384R1\n"); return gnutls_assert_val(0); } } break; } } return 1; }
/* verifies if the certificate is properly signed. * returns GNUTLS_E_PK_VERIFY_SIG_FAILED on failure and 1 on success. * * 'data' is the signed data * 'signature' is the signature! */ static int _gnutls_x509_verify_data(gnutls_sign_algorithm_t sign, const gnutls_datum_t * data, const gnutls_datum_t * signature, gnutls_x509_crt_t cert, gnutls_x509_crt_t issuer, unsigned vflags) { gnutls_pk_params_st params; gnutls_pk_algorithm_t issuer_pk; int ret; gnutls_x509_spki_st sign_params; const gnutls_sign_entry_st *se; /* Read the MPI parameters from the issuer's certificate. */ ret = _gnutls_x509_crt_get_mpis(issuer, ¶ms); if (ret < 0) { gnutls_assert(); return ret; } issuer_pk = gnutls_x509_crt_get_pk_algorithm(issuer, NULL); se = _gnutls_sign_to_entry(sign); if (se == NULL) return gnutls_assert_val(GNUTLS_E_UNSUPPORTED_SIGNATURE_ALGORITHM); if (cert != NULL) { ret = _gnutls_x509_read_sign_params(cert->cert, "signatureAlgorithm", &sign_params); if (ret < 0) { gnutls_assert(); goto cleanup; } ret = _gnutls_x509_validate_sign_params(issuer_pk, issuer->cert, "tbsCertificate." "subjectPublicKeyInfo." "algorithm", &sign_params); if (ret < 0) { gnutls_assert(); goto cleanup; } } else { memcpy(&sign_params, ¶ms.spki, sizeof(gnutls_x509_spki_st)); sign_params.pk = se->pk; if (sign_params.pk == GNUTLS_PK_RSA_PSS) sign_params.rsa_pss_dig = se->hash; } ret = pubkey_verify_data(se, hash_to_entry(se->hash), data, signature, ¶ms, &sign_params, vflags); if (ret < 0) { gnutls_assert(); } cleanup: /* release all allocated MPIs */ gnutls_pk_params_release(¶ms); return ret; }
/* Like above but it accepts a parsed certificate instead. */ int _gnutls_x509_crt_to_gcert (gnutls_cert * gcert, gnutls_x509_crt_t cert, unsigned int flags) { int ret = 0; memset (gcert, 0, sizeof (gnutls_cert)); gcert->cert_type = GNUTLS_CRT_X509; if (!(flags & CERT_NO_COPY)) { #define SMALL_DER 512 opaque *der; size_t der_size = SMALL_DER; /* initially allocate a bogus size, just in case the certificate * fits in it. That way we minimize the DER encodings performed. */ der = gnutls_malloc (SMALL_DER); if (der == NULL) { gnutls_assert (); return GNUTLS_E_MEMORY_ERROR; } ret = gnutls_x509_crt_export (cert, GNUTLS_X509_FMT_DER, der, &der_size); if (ret < 0 && ret != GNUTLS_E_SHORT_MEMORY_BUFFER) { gnutls_assert (); gnutls_free (der); return ret; } if (ret == GNUTLS_E_SHORT_MEMORY_BUFFER) { der = gnutls_realloc (der, der_size); if (der == NULL) { gnutls_assert (); return GNUTLS_E_MEMORY_ERROR; } ret = gnutls_x509_crt_export (cert, GNUTLS_X509_FMT_DER, der, &der_size); if (ret < 0) { gnutls_assert (); gnutls_free (der); return ret; } } gcert->raw.data = der; gcert->raw.size = der_size; } else /* now we have 0 or a bitwise or of things to decode */ flags ^= CERT_NO_COPY; if (flags & CERT_ONLY_EXTENSIONS || flags == 0) { gnutls_x509_crt_get_key_usage (cert, &gcert->key_usage, NULL); gcert->version = gnutls_x509_crt_get_version (cert); } gcert->subject_pk_algorithm = gnutls_x509_crt_get_pk_algorithm (cert, NULL); if (flags & CERT_ONLY_PUBKEY || flags == 0) { gcert->params_size = MAX_PUBLIC_PARAMS_SIZE; ret = _gnutls_x509_crt_get_mpis (cert, gcert->params, &gcert->params_size); if (ret < 0) { gnutls_assert (); return ret; } } return 0; }
int _gnutls_x509_verify_algorithm (gnutls_mac_algorithm_t * hash, const gnutls_datum_t * signature, const gnutls_x509_crt_t issuer) { bigint_t issuer_params[MAX_PUBLIC_PARAMS_SIZE]; opaque digest[MAX_HASH_SIZE]; gnutls_datum_t decrypted; int issuer_params_size; int digest_size; int ret, i; issuer_params_size = MAX_PUBLIC_PARAMS_SIZE; ret = _gnutls_x509_crt_get_mpis (issuer, issuer_params, &issuer_params_size); if (ret < 0) { gnutls_assert (); return ret; } switch (gnutls_x509_crt_get_pk_algorithm (issuer, NULL)) { case GNUTLS_PK_DSA: if (hash) *hash = _gnutls_dsa_q_to_hash (issuer_params[1]); ret = 0; break; case GNUTLS_PK_RSA: ret = _gnutls_pkcs1_rsa_decrypt (&decrypted, signature, issuer_params, issuer_params_size, 1); if (ret < 0) { gnutls_assert (); goto cleanup; } digest_size = sizeof (digest); if ((ret = decode_ber_digest_info (&decrypted, hash, digest, &digest_size)) != 0) { gnutls_assert (); _gnutls_free_datum (&decrypted); goto cleanup; } _gnutls_free_datum (&decrypted); if (digest_size != _gnutls_hash_get_algo_len (*hash)) { gnutls_assert (); ret = GNUTLS_E_ASN1_GENERIC_ERROR; goto cleanup; } ret = 0; break; default: gnutls_assert (); ret = GNUTLS_E_INTERNAL_ERROR; } cleanup: /* release allocated mpis */ for (i = 0; i < issuer_params_size; i++) { _gnutls_mpi_release (&issuer_params[i]); } return ret; }