예제 #1
0
static VALUE
ossl_x509stctx_get_chain(VALUE self)
{
    X509_STORE_CTX *ctx;
    STACK_OF(X509) *chain;
    X509 *x509;
    int i, num;
    VALUE ary;

    GetX509StCtx(self, ctx);
    if((chain = X509_STORE_CTX_get_chain(ctx)) == NULL){
        return Qnil;
    }
    if((num = sk_X509_num(chain)) < 0){
	OSSL_Debug("certs in chain < 0???");
	return rb_ary_new();
    }
    ary = rb_ary_new2(num);
    for(i = 0; i < num; i++) {
	x509 = sk_X509_value(chain, i);
	rb_ary_push(ary, ossl_x509_new(x509));
    }

    return ary;
}
예제 #2
0
static int verify_callback(int preverify_ok, X509_STORE_CTX *ctx)
{
	int i, j;

	/*
	 * Preverify checks the platform's certificate store; don't
	 * allow any chain that doesn't already validate according to
	 * that.
	 */
	if (!preverify_ok)
		return 0;

	/* check each certificate in the chain against our built-in pinlist. */
	STACK_OF(X509) *chain = X509_STORE_CTX_get_chain(ctx);
	if (!chain)
		die("No certificate chain available");

	bool found = false;
	for (i=0; i < sk_X509_num(chain); i++) {
		_cleanup_free_ char *spki_hash = NULL;
		spki_hash = hash_subject_pubkey_info(sk_X509_value(chain, i));
		if (!spki_hash)
			continue;

		for (j=0; j < (int) ARRAY_SIZE(PK_PINS); j++) {
			if (strcmp(PK_PINS[j], spki_hash) == 0) {
				found = true;
				break;
			}
		}
	}

	return found;
}
예제 #3
0
json::value get_cert_chain_information(boost::asio::ssl::verify_context &verifyCtx)
{
    X509_STORE_CTX *storeContext = verifyCtx.native_handle();

    STACK_OF(X509) *certStack = X509_STORE_CTX_get_chain(storeContext);

    const int numCerts = sk_X509_num(certStack);
    if (numCerts < 0)
    {
        return {};
    }
 
    json::value certChainInformation;

    for (int index = 0; index < numCerts; ++index)
    {
        X509 *cert = sk_X509_value(certStack, index);

        json::value certInformation;
        certInformation[U("Issuer")] = json::value::string(get_issuer_from_cert(cert));
        certInformation[U("Subject")] = json::value::string(get_subject_from_cert(cert));
        certInformation[U("FingerPrint")] = json::value::string(get_fingerprint_from_cert(cert));

        utility::stringstream_t countInfo;
        countInfo << "Certificate: " << index;
        certChainInformation[countInfo.str()] = certInformation;
    }
    return certChainInformation;
}
예제 #4
0
bool ssl_options_t::has_fingerprint(boost::asio::ssl::verify_context &ctx) const
{
  // can we check the certificate against a list of fingerprints?
  if (!fingerprints_.empty()) {
    X509_STORE_CTX *sctx = ctx.native_handle();
    if (!sctx)
    {
      MERROR("Error getting verify_context handle");
      return false;
    }

    X509* cert = nullptr;
    const STACK_OF(X509)* chain = X509_STORE_CTX_get_chain(sctx);
    if (!chain || sk_X509_num(chain) < 1 || !(cert = sk_X509_value(chain, 0)))
    {
      MERROR("No certificate found in verify_context");
      return false;
    }

    // buffer for the certificate digest and the size of the result
    std::vector<uint8_t> digest(EVP_MAX_MD_SIZE);
    unsigned int size{ 0 };

    // create the digest from the certificate
    if (!X509_digest(cert, EVP_sha256(), digest.data(), &size)) {
      MERROR("Failed to create certificate fingerprint");
      return false;
    }

    // strip unnecessary bytes from the digest
    digest.resize(size);

    return std::binary_search(fingerprints_.begin(), fingerprints_.end(), digest);
  }
예제 #5
0
/* find the issuer certificate without lookups */
NOEXPORT X509 *get_current_issuer(X509_STORE_CTX *callback_ctx) {
    STACK_OF(X509) *chain;
    int depth;

    chain=X509_STORE_CTX_get_chain(callback_ctx);
    depth=X509_STORE_CTX_get_error_depth(callback_ctx);
    if(depth<sk_X509_num(chain)-1) /* not the root CA cert */
        ++depth; /* index of the issuer cert */
    return sk_X509_value(chain, depth);
}
예제 #6
0
bool verify_cert_chain_platform_specific(boost::asio::ssl::verify_context &verifyCtx, const std::string &hostName)
{
    X509_STORE_CTX *storeContext = verifyCtx.native_handle();
    int currentDepth = X509_STORE_CTX_get_error_depth(storeContext);
    if (currentDepth != 0)
    {
        return true;
    }

    STACK_OF(X509) *certStack = X509_STORE_CTX_get_chain(storeContext);
    const int numCerts = sk_X509_num(certStack);
    if (numCerts < 0)
    {
        return false;
    }

    std::vector<std::string> certChain;
    certChain.reserve(numCerts);
    for (int i = 0; i < numCerts; ++i)
    {
        X509 *cert = sk_X509_value(certStack, i);

        // Encode into DER format into raw memory.
        int len = i2d_X509(cert, nullptr);
        if (len < 0)
        {
            return false;
        }

        std::string certData;
        certData.resize(len);
        unsigned char * buffer = reinterpret_cast<unsigned char *>(&certData[0]);
        len = i2d_X509(cert, &buffer);
        if (len < 0)
        {
            return false;
        }

        certChain.push_back(std::move(certData));
    }

    auto verify_result = verify_X509_cert_chain(certChain, hostName);

    // The Windows Crypto APIs don't do host name checks, use Boost's implementation.
#if defined(_WIN32)
    if (verify_result)
    {
        boost::asio::ssl::rfc2818_verification rfc2818(hostName);
        verify_result = rfc2818(verify_result, verifyCtx);
    }
#endif
    return verify_result;
}
예제 #7
0
std::vector<std::string> get_cert_chain_public_keys(boost::asio::ssl::verify_context &verifyCtx)
{
    std::vector<std::string> certChain;
 
    X509_STORE_CTX *storeContext = verifyCtx.native_handle();
    
    STACK_OF(X509) *certStack = X509_STORE_CTX_get_chain(storeContext);
    const int numCerts = sk_X509_num(certStack);
    if (numCerts < 0)
    {
        return certChain;
    }
    
    certChain.reserve(numCerts);

    for (int i = 0; i < numCerts; ++i)
    {
        X509 *cert = sk_X509_value(certStack, i);
        
        certChain.push_back(get_public_key_from_cert(cert));
    }
    
    return certChain;
}
예제 #8
0
/*============================================================================
 * OpcUa_P_OpenSSL_PKI_ValidateCertificate
 *===========================================================================*/
OpcUa_StatusCode OpcUa_P_OpenSSL_PKI_ValidateCertificate(
    OpcUa_PKIProvider*          a_pProvider,
    OpcUa_ByteString*           a_pCertificate,
    OpcUa_Void*                 a_pCertificateStore,
    OpcUa_Int*                  a_pValidationCode /* Validation return codes from OpenSSL */
    )
{
    OpcUa_P_OpenSSL_CertificateStore_Config*    pCertificateStoreCfg;

    const unsigned char* p;

    X509*               pX509Certificate        = OpcUa_Null;
    STACK_OF(X509)*     pX509Chain              = OpcUa_Null;
    X509_STORE_CTX*     verify_ctx              = OpcUa_Null;    /* holds data used during verification process */
    char                CertFile[MAX_PATH];
    struct dirent **dirlist = NULL;
    int numCertificates = 0, i;

OpcUa_InitializeStatus(OpcUa_Module_P_OpenSSL, "PKI_ValidateCertificate");

    OpcUa_ReturnErrorIfArgumentNull(a_pProvider);
    OpcUa_ReturnErrorIfArgumentNull(a_pProvider->Handle);
    OpcUa_ReturnErrorIfArgumentNull(a_pCertificate);
    OpcUa_ReturnErrorIfArgumentNull(a_pCertificateStore);
    OpcUa_ReturnErrorIfArgumentNull(a_pValidationCode);

    pCertificateStoreCfg = (OpcUa_P_OpenSSL_CertificateStore_Config*)a_pProvider->Handle;

    /* convert DER encoded bytestring certificate to openssl X509 certificate */
    p = a_pCertificate->Data;
    if(!(pX509Certificate = d2i_X509((X509**)OpcUa_Null, &p, a_pCertificate->Length)))
    {
        OpcUa_GotoErrorWithStatus(OpcUa_Bad);
    }

    while(p < a_pCertificate->Data + a_pCertificate->Length)
    {
        X509* pX509AddCertificate;
        if(!(pX509AddCertificate = d2i_X509((X509**)OpcUa_Null, &p, a_pCertificate->Data + a_pCertificate->Length - p)))
        {
            OpcUa_GotoErrorWithStatus(OpcUa_Bad);
        }
        if(pX509Chain == NULL)
        {
            pX509Chain = sk_X509_new_null();
            OpcUa_GotoErrorIfAllocFailed(pX509Chain);
        }
        if(!sk_X509_push(pX509Chain, pX509AddCertificate))
        {
            X509_free(pX509AddCertificate);
            OpcUa_GotoErrorWithStatus(OpcUa_Bad);
        }
    }

    /* create verification context and initialize it */
    if(!(verify_ctx = X509_STORE_CTX_new()))
    {
        OpcUa_GotoErrorWithStatus(OpcUa_Bad);
    }

#if (OPENSSL_VERSION_NUMBER > 0x00907000L)
    if(X509_STORE_CTX_init(verify_ctx, (X509_STORE*)a_pCertificateStore, pX509Certificate, pX509Chain) != 1)
    {
        OpcUa_GotoErrorWithStatus(OpcUa_Bad);
    }
#else
    X509_STORE_CTX_init(verify_ctx, (X509_STORE*)a_pCertificateStore, pX509Certificate, pX509Chain);
#endif

    if(X509_STORE_CTX_set_app_data(verify_ctx, pCertificateStoreCfg) != 1)
    {
        OpcUa_GotoErrorWithStatus(OpcUa_Bad);
    }

    if((pCertificateStoreCfg->Flags & OPCUA_P_PKI_OPENSSL_CHECK_REVOCATION_ALL) == OPCUA_P_PKI_OPENSSL_CHECK_REVOCATION_ALL_EXCEPT_SELF_SIGNED
        && !verify_ctx->check_issued(verify_ctx, pX509Certificate, pX509Certificate))
    {
        /* set the flags of the store so that CRLs are consulted */
        X509_STORE_CTX_set_flags(verify_ctx, X509_V_FLAG_CRL_CHECK | X509_V_FLAG_CRL_CHECK_ALL);
    }

    /* verify the certificate */
    *a_pValidationCode = X509_V_OK;
    if(X509_verify_cert(verify_ctx) <= 0)
    {
        *a_pValidationCode = verify_ctx->error;
        switch(verify_ctx->error)
        {
        case X509_V_ERR_CERT_HAS_EXPIRED:
        case X509_V_ERR_CERT_NOT_YET_VALID:
        case X509_V_ERR_CRL_NOT_YET_VALID:
        case X509_V_ERR_CRL_HAS_EXPIRED:
        case X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD:
        case X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD:
        case X509_V_ERR_ERROR_IN_CRL_LAST_UPDATE_FIELD:
        case X509_V_ERR_ERROR_IN_CRL_NEXT_UPDATE_FIELD:
            {
                uStatus = OpcUa_BadCertificateTimeInvalid;
                break;
            }
        case X509_V_ERR_CERT_REVOKED:
            {
                uStatus = OpcUa_BadCertificateRevoked;
                break;
            }
        case X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT:
        case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY:
        case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT:
            {
                uStatus = OpcUa_BadCertificateUntrusted;
                break;
            }
        case X509_V_ERR_CERT_SIGNATURE_FAILURE:
            {
                uStatus = OpcUa_BadSecurityChecksFailed;
                break;
            }
        default:
            {
                uStatus = OpcUa_BadCertificateInvalid;
            }
        }
        OpcUa_GotoErrorIfBad(uStatus);
    }

    if(pCertificateStoreCfg->Flags & OPCUA_P_PKI_OPENSSL_REQUIRE_CHAIN_CERTIFICATE_IN_TRUST_LIST)
    {
        FILE*            pCertificateFile;
        X509*            pTrustCert;
        STACK_OF(X509)*  chain;
        int              trusted, n;

        chain = X509_STORE_CTX_get_chain(verify_ctx);
        trusted = 0;
        if(pCertificateStoreCfg->CertificateTrustListLocation == NULL || pCertificateStoreCfg->CertificateTrustListLocation[0] == '\0')
        {
            uStatus = OpcUa_Bad;
            OpcUa_GotoErrorIfBad(uStatus);
        }

        numCertificates = scandir(pCertificateStoreCfg->CertificateTrustListLocation, &dirlist, certificate_filter_der, alphasort);
        for (i=0; i<numCertificates; i++)
        {
            uStatus = OpcUa_P_OpenSSL_BuildFullPath(pCertificateStoreCfg->CertificateTrustListLocation, dirlist[i]->d_name, MAX_PATH, CertFile);
            OpcUa_GotoErrorIfBad(uStatus);

            /* read DER certificates */
            pCertificateFile = fopen(CertFile, "r");
            if(pCertificateFile == OpcUa_Null)
            {
                continue; /* ignore access errors */
            }

            pTrustCert = d2i_X509_fp(pCertificateFile, (X509**)OpcUa_Null);
            fclose(pCertificateFile);
            if(pTrustCert == OpcUa_Null)
            {
                continue; /* ignore parse errors */
            }

            for(n = 0; n < sk_X509_num(chain); n++)
            {
                if (X509_cmp(sk_X509_value(chain, n), pTrustCert) == 0)
                    break;
            }

            X509_free(pTrustCert);
            if(n < sk_X509_num(chain))
            {
                trusted = 1;
                break;
            }
        }
        for (i=0; i<numCertificates; i++)
        {
            free(dirlist[i]);
        }
        free(dirlist);
        dirlist = NULL;

        if(!trusted)
        {
            uStatus = OpcUa_BadCertificateUntrusted;
            OpcUa_GotoErrorIfBad(uStatus);
        }
    }

    X509_STORE_CTX_free(verify_ctx);
    X509_free(pX509Certificate);
    if(pX509Chain != OpcUa_Null)
    {
        sk_X509_pop_free(pX509Chain, X509_free);
    }

OpcUa_ReturnStatusCode;
OpcUa_BeginErrorHandling;

    if(dirlist != NULL)
    {
        for (i=0; i<numCertificates; i++)
        {
            free(dirlist[i]);
        }
        free(dirlist);
    }

    if(verify_ctx != OpcUa_Null)
    {
        X509_STORE_CTX_free(verify_ctx);
    }

    if(pX509Certificate != OpcUa_Null)
    {
        X509_free(pX509Certificate);
    }

    if(pX509Chain != OpcUa_Null)
    {
        sk_X509_pop_free(pX509Chain, X509_free);
    }

OpcUa_FinishErrorHandling;
}
예제 #9
0
STACK_OF(X509) * X509_STORE_CTX_get0_chain(X509_STORE_CTX* ctx) {
  return X509_STORE_CTX_get_chain(ctx);
}
예제 #10
0
// take certificate hashes, check their validity and output json that
// will indicate which certificate were used for verification, whatever
// the chain was trusted and if all certificates needed for verification
// (with the exception of root CA) were present in hashes
int process_chain(const char **cert_hashes)
{
    int ret;
    int rc; // return code from function
    char *f_name;

    X509 *cert;
    X509 *x509;

    X509_STORE *store;

    X509_STORE_CTX *csc;

    STACK_OF(X509) *ustack;
    STACK_OF(X509) *vstack;

    // load certificates to temp structures

    // first the end entity cert
    // (EE cert needs to be passed separately to OpenSSL verification context)
    f_name = hash_to_filename(cert_hashes[0]);
    if (f_name == NULL)
        return 1;

    cert = load_cert(f_name);
    free(f_name);
    if (cert == NULL) {
        printf("can't load certificate!\n");
        return 1;
    }

    // then the intermediate certificates
    ustack = sk_X509_new_null();

    for (int i=1; cert_hashes[i]!=NULL; i++) {
        //printf(".\n");
        f_name = hash_to_filename(cert_hashes[i]);
        if (f_name == NULL) {
            // file not found
            continue;
        }
        x509 = load_cert(f_name);
        if (x509 == NULL) {
            // loading cert failed
            continue;
        }
        sk_X509_push(ustack, x509);
        free(f_name);
    }

    // first try with just trusted certificates

    store = SSL_CTX_get_cert_store(trusted_only);
    if (store == NULL) {
        fprintf(stderr, "store init failed\n");
        return 1;
    }
    X509_STORE_set_flags(store, X509_V_FLAG_TRUSTED_FIRST);

    csc = X509_STORE_CTX_new();

    ret = X509_STORE_CTX_init(csc, store, cert, ustack);
    if (ret != 1) {
        return 1;
    }

    ret = X509_verify_cert(csc);

    if (ret != 1) {
       // printf("%s\n", X509_verify_cert_error_string(csc->error));
    } else {
        // chain is complete, output certificate hashes
        printf("{\"chain\":\"complete\",\"certificates\":[");
        vstack = X509_STORE_CTX_get_chain(csc);
        for(int i=0; i<sk_X509_num(vstack); i++) {
            X509 *c = sk_X509_value(vstack, i);

            const EVP_MD *digest;
            unsigned char md[EVP_MAX_MD_SIZE];
            int n;
            digest = EVP_get_digestbyname("sha256");
            X509_digest(c, digest, md, &n);
            printf("\"");
            for(int i=0; i<n; i++) {
                printf("%02x", md[i]);
            }
            printf("\"");
            if (i+1 < sk_X509_num(vstack)) {
                printf(",");
            }
        }
        printf("]}");
        X509_STORE_CTX_free(csc);
        sk_X509_pop_free(ustack, X509_free);
        X509_free(cert);
        return 0;
    }
    X509_STORE_CTX_free(csc);

    // validation failed with just the trust anchors, retry with all
    // known intermediate certificates

    store = SSL_CTX_get_cert_store(all_CAs);
    if (store == NULL) {
        fprintf(stderr, "store init failed\n");
        return 1;
    }
    X509_STORE_set_flags(store, X509_V_FLAG_TRUSTED_FIRST);

    csc = X509_STORE_CTX_new();

    ret = X509_STORE_CTX_init(csc, store, cert, ustack);
    if (ret != 1) {
        return 1;
    }

    ret = X509_verify_cert(csc);
    if (ret != 1) {
        // certificate untrusted
        printf("{\"chain\":\"untrusted\"}");
    } else {
        // chain successfully verified using all certificates,
        // print all the certs used to verify it
        printf("{\"chain\":\"incomplete\",\"certificates\":[");
        vstack = X509_STORE_CTX_get_chain(csc);
        for(int i=0; i<sk_X509_num(vstack); i++) {
            X509 *c = sk_X509_value(vstack, i);

            const EVP_MD *digest;
            unsigned char md[EVP_MAX_MD_SIZE];
            int n;
            digest = EVP_get_digestbyname("sha256");
            X509_digest(c, digest, md, &n);
            printf("\"");
            for(int i=0; i<n; i++) {
                printf("%02x", md[i]);
            }
            printf("\"");
            if (i+1 < sk_X509_num(vstack)) {
                printf(",");
            }
        }
        printf("]}");
    }

    X509_STORE_CTX_free(csc);
    sk_X509_pop_free(ustack, X509_free);
    X509_free(cert);

    return 0;
}