Example #1
0
/**
 * OpenSSL certificate chain verification callback
 * Verifies certificate chain, setting up context for fetch_curl_verify_callback
 */
static int fetch_curl_cert_verify_callback(X509_STORE_CTX *x509_ctx, void *parm)
{
	int ok;

	/* Store fetch struct in context for verify callback */
	ok = X509_STORE_CTX_set_app_data(x509_ctx, parm);

	/* and verify the certificate chain */
	if (ok)
		ok = X509_verify_cert(x509_ctx);

	return ok;
}
Example #2
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;
}