示例#1
0
/**
 * gnutls_x509_trust_list_get_issuer:
 * @list: The structure of the list
 * @cert: is the certificate to find issuer for
 * @issuer: Will hold the issuer if any. Should be treated as constant.
 * @flags: Use zero or %GNUTLS_TL_GET_COPY
 *
 * This function will find the issuer of the given certificate.
 * If the flag %GNUTLS_TL_GET_COPY is specified a copy of the issuer
 * will be returned which must be freed using gnutls_x509_crt_deinit().
 * Note that the flag %GNUTLS_TL_GET_COPY is required for this function
 * to work with PKCS #11 trust lists in a thread-safe way.
 *
 * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a
 *   negative error value.
 *
 * Since: 3.0
 **/
int gnutls_x509_trust_list_get_issuer(gnutls_x509_trust_list_t list,
				      gnutls_x509_crt_t cert,
				      gnutls_x509_crt_t * issuer,
				      unsigned int flags)
{
	int ret;

	ret = trust_list_get_issuer(list, cert, issuer, flags);
	if (ret == 0) {
		return 0;
	}

#ifdef ENABLE_PKCS11
	if (ret < 0 && list->pkcs11_token) {
		gnutls_x509_crt_t crt;
		gnutls_datum_t der = {NULL, 0};
		/* use the token for verification */
		ret = gnutls_pkcs11_get_raw_issuer(list->pkcs11_token, cert, &der,
			GNUTLS_X509_FMT_DER, 0);
		if (ret < 0) {
			gnutls_assert();
			return ret;
		}

		ret = gnutls_x509_crt_init(&crt);
		if (ret < 0) {
			gnutls_free(der.data);
			return gnutls_assert_val(ret);
		}

		ret = gnutls_x509_crt_import(crt, &der, GNUTLS_X509_FMT_DER);
		gnutls_free(der.data);
		if (ret < 0) {
			gnutls_x509_crt_deinit(crt);
			return gnutls_assert_val(ret);
		}

		if (flags & GNUTLS_TL_GET_COPY) {
			*issuer = crt;
			return 0;
		} else {
			/* we add this CA to the keep_cert list in order to make it
			 * persistent. It will be deallocated when the trust list is.
			 */
			ret = trust_list_add_compat(list, crt);
			if (ret < 0) {
				gnutls_x509_crt_deinit(crt);
				return gnutls_assert_val(ret);
			}
			*issuer = crt;
			return ret;
		}
	}
#endif
	return ret;
}
示例#2
0
文件: verify.c 项目: GostCrypt/GnuTLS
/* Verify X.509 certificate chain using a PKCS #11 token.
 *
 * Note that the return value is an OR of GNUTLS_CERT_* elements.
 *
 * Unlike the non-PKCS#11 version, this function accepts a key purpose
 * (from GNUTLS_KP_...). That is because in the p11-kit trust modules
 * anchors are mixed and get assigned a purpose.
 *
 * This function verifies a X.509 certificate list. The certificate
 * list should lead to a trusted certificate in order to be trusted.
 */
unsigned int
_gnutls_pkcs11_verify_crt_status(const char* url,
				const gnutls_x509_crt_t * certificate_list,
				unsigned clist_size,
				const char *purpose,
				unsigned int flags,
				gnutls_verify_output_function func)
{
	int ret;
	unsigned int status = 0, i;
	gnutls_x509_crt_t issuer = NULL;
	gnutls_datum_t raw_issuer = {NULL, 0};
	time_t now = gnutls_time(0);

	if (clist_size > 1) {
		/* Check if the last certificate in the path is self signed.
		 * In that case ignore it (a certificate is trusted only if it
		 * leads to a trusted party by us, not the server's).
		 *
		 * This prevents from verifying self signed certificates against
		 * themselves. This (although not bad) caused verification
		 * failures on some root self signed certificates that use the
		 * MD2 algorithm.
		 */
		if (gnutls_x509_crt_check_issuer
		    (certificate_list[clist_size - 1],
		     certificate_list[clist_size - 1]) != 0) {
			clist_size--;
		}
	}

	/* We want to shorten the chain by removing the cert that matches
	 * one of the certs we trust and all the certs after that i.e. if
	 * cert chain is A signed-by B signed-by C signed-by D (signed-by
	 * self-signed E but already removed above), and we trust B, remove
	 * B, C and D. */
	if (!(flags & GNUTLS_VERIFY_DO_NOT_ALLOW_SAME))
		i = 0;		/* also replace the first one */
	else
		i = 1;		/* do not replace the first one */

	for (; i < clist_size; i++) {
		unsigned vflags;

		if (i == 0) /* in the end certificate do full comparison */
			vflags = GNUTLS_PKCS11_OBJ_FLAG_PRESENT_IN_TRUSTED_MODULE|
				GNUTLS_PKCS11_OBJ_FLAG_COMPARE|GNUTLS_PKCS11_OBJ_FLAG_RETRIEVE_TRUSTED;
		else
			vflags = GNUTLS_PKCS11_OBJ_FLAG_PRESENT_IN_TRUSTED_MODULE|
				GNUTLS_PKCS11_OBJ_FLAG_COMPARE_KEY|GNUTLS_PKCS11_OBJ_FLAG_RETRIEVE_TRUSTED;

		if (gnutls_pkcs11_crt_is_known (url, certificate_list[i], vflags) != 0) {

			if (!(flags & GNUTLS_VERIFY_DISABLE_TRUSTED_TIME_CHECKS) &&
				!(flags & GNUTLS_VERIFY_DISABLE_TIME_CHECKS)) {
				status |=
				    check_time_status(certificate_list[i], now);
				if (status != 0) {
					if (func)
						func(certificate_list[i], certificate_list[i], NULL, status);
					return status;
				}
			}
			if (func)
				func(certificate_list[i],
				     certificate_list[i], NULL, status);

			clist_size = i;
			break;
		}
		/* clist_size may have been changed which gets out of loop */
	}

	if (clist_size == 0) {
		/* The certificate is already present in the trusted certificate list.
		 * Nothing to verify. */
		return status;
	}

	/* check for blacklists */
	for (i = 0; i < clist_size; i++) {
		if (gnutls_pkcs11_crt_is_known (url, certificate_list[i], 
			GNUTLS_PKCS11_OBJ_FLAG_PRESENT_IN_TRUSTED_MODULE|
			GNUTLS_PKCS11_OBJ_FLAG_RETRIEVE_DISTRUSTED) != 0) {
			status |= GNUTLS_CERT_INVALID;
			status |= GNUTLS_CERT_REVOKED;
			if (func)
				func(certificate_list[i], certificate_list[i], NULL, status);
			goto cleanup;
		}
	}

	/* check against issuer */
	ret = gnutls_pkcs11_get_raw_issuer(url, certificate_list[clist_size - 1],
					   &raw_issuer, GNUTLS_X509_FMT_DER,
					   GNUTLS_PKCS11_OBJ_FLAG_OVERWRITE_TRUSTMOD_EXT|GNUTLS_PKCS11_OBJ_FLAG_PRESENT_IN_TRUSTED_MODULE);
	if (ret < 0) {
		gnutls_assert();
		if (ret == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE && clist_size > 2) {

			/* check if the last certificate in the chain is present
			 * in our trusted list, and if yes, verify against it. */
			ret = gnutls_pkcs11_crt_is_known(url, certificate_list[clist_size - 1],
				GNUTLS_PKCS11_OBJ_FLAG_RETRIEVE_TRUSTED|GNUTLS_PKCS11_OBJ_FLAG_COMPARE);
			if (ret != 0) {
				return _gnutls_verify_crt_status(certificate_list, clist_size,
					&certificate_list[clist_size - 1], 1, flags,
					purpose, func);
			}
		}

		status |= GNUTLS_CERT_INVALID;
		status |= GNUTLS_CERT_SIGNER_NOT_FOUND;
		/* verify the certificate list against 0 trusted CAs in order
		 * to get, any additional flags from the certificate list (e.g.,
		 * insecure algorithms or expired */
		status |= _gnutls_verify_crt_status(certificate_list, clist_size,
						    NULL, 0, flags, purpose, func);
		goto cleanup;
	}

	ret = gnutls_x509_crt_init(&issuer);
	if (ret < 0) {
		gnutls_assert();
		status |= GNUTLS_CERT_INVALID;
		status |= GNUTLS_CERT_SIGNER_NOT_FOUND;
		goto cleanup;
	}

	ret = gnutls_x509_crt_import(issuer, &raw_issuer, GNUTLS_X509_FMT_DER);
	if (ret < 0) {
		gnutls_assert();
		status |= GNUTLS_CERT_INVALID;
		status |= GNUTLS_CERT_SIGNER_NOT_FOUND;
		goto cleanup;
	}

	/* check if the raw issuer is blacklisted (it can happen if
	 * the issuer is both in the trusted list and the blacklisted)
	 */
	if (gnutls_pkcs11_crt_is_known (url, issuer,
		GNUTLS_PKCS11_OBJ_FLAG_PRESENT_IN_TRUSTED_MODULE|
		GNUTLS_PKCS11_OBJ_FLAG_RETRIEVE_DISTRUSTED) != 0) {
		status |= GNUTLS_CERT_INVALID;
		status |= GNUTLS_CERT_SIGNER_NOT_FOUND; /* if the signer is revoked - it is as if it doesn't exist */
		goto cleanup;
	}

	/* security modules that provide trust, bundle all certificates (of all purposes)
	 * together. In software that doesn't specify any purpose assume the default to
	 * be www-server. */
	ret = _gnutls_check_key_purpose(issuer, purpose==NULL?GNUTLS_KP_TLS_WWW_SERVER:purpose, 0);
	if (ret != 1) {
		gnutls_assert();
		status |= GNUTLS_CERT_INVALID;
		status |= GNUTLS_CERT_SIGNER_NOT_FOUND;
		goto cleanup;
	}

	status = _gnutls_verify_crt_status(certificate_list, clist_size,
				&issuer, 1, flags, purpose, func);

cleanup:
	gnutls_free(raw_issuer.data);
	if (issuer != NULL)
		gnutls_x509_crt_deinit(issuer);

	return status;
}
示例#3
0
void
pkcs11_export_chain(FILE * outfile, const char *url, unsigned int flags,
	      common_info_st * info)
{
	gnutls_pkcs11_obj_t obj;
	gnutls_x509_crt_t xcrt;
	gnutls_datum_t t;
	int ret;
	unsigned int obj_flags = flags;

	pkcs11_common(info);

	FIX(url, outfile, 0, info);

	ret = gnutls_pkcs11_obj_init(&obj);
	if (ret < 0) {
		fprintf(stderr, "Error in %s:%d: %s\n", __func__, __LINE__,
			gnutls_strerror(ret));
		exit(1);
	}

	ret = gnutls_pkcs11_obj_import_url(obj, url, obj_flags);
	if (ret < 0) {
		fprintf(stderr, "Error in %s:%d: %s\n", __func__, __LINE__,
			gnutls_strerror(ret));
		exit(1);
	}

	/* make a crt */
	ret = gnutls_x509_crt_init(&xcrt);
	if (ret < 0) {
		fprintf(stderr, "Error in %s:%d: %s\n", __func__, __LINE__,
			gnutls_strerror(ret));
		exit(1);
	}

	ret = gnutls_x509_crt_import_pkcs11(xcrt, obj);
	if (ret < 0) {
        	fprintf(stderr, "Error in %s:%d: %s\n", __func__,
				__LINE__, gnutls_strerror(ret));
                exit(1);
        }

	ret = gnutls_pkcs11_obj_export3(obj, GNUTLS_X509_FMT_PEM, &t);
	if (ret < 0) {
        	fprintf(stderr, "Error in %s:%d: %s\n", __func__,
				__LINE__, gnutls_strerror(ret));
                exit(1);
        }
	fwrite(t.data, 1, t.size, outfile);
       	fputs("\n\n", outfile);
        gnutls_free(t.data);

        gnutls_pkcs11_obj_deinit(obj);
        
        do {
                ret = gnutls_pkcs11_get_raw_issuer(url, xcrt, &t, GNUTLS_X509_FMT_PEM, 0);
        	if (ret == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE)
	                break;
        	if (ret < 0) {
                	fprintf(stderr, "Error in %s:%d: %s\n", __func__,
		        		__LINE__, gnutls_strerror(ret));
                        exit(1);
                }
                
        	fwrite(t.data, 1, t.size, outfile);
               	fputs("\n\n", outfile);

               	gnutls_x509_crt_deinit(xcrt);

               	ret = gnutls_x509_crt_init(&xcrt);
        	if (ret < 0) {
                	fprintf(stderr, "Error in %s:%d: %s\n", __func__,
		        		__LINE__, gnutls_strerror(ret));
                        exit(1);
                }

               	ret = gnutls_x509_crt_import(xcrt, &t, GNUTLS_X509_FMT_PEM);
        	if (ret < 0) {
                	fprintf(stderr, "Error in %s:%d: %s\n", __func__,
		        		__LINE__, gnutls_strerror(ret));
                        exit(1);
                }

                gnutls_free(t.data);
                
                ret = gnutls_x509_crt_check_issuer(xcrt, xcrt);
                if (ret != 0) {
                        /* self signed */
                        break;
                }
                
        } while(1);
        
	UNFIX;
	return;
}