<html>
  <head>
    <meta content="text/html; charset=UTF-8" http-equiv="Content-Type">
  </head>
  <body bgcolor="#FFFFFF" text="#000000">
    On 04.10.2015 21:08, Walter H. wrote:
    <blockquote cite="mid:5611792E.2010308@mathemainzel.info"
      type="cite">Hello,
      <br>
      <br>
      does anybody know if squid does certificate checks and how to tell
      squid to do so;
      <br>
      <br>
      this is a site with a revoked certificate
      <br>
      <a class="moz-txt-link-freetext" href="https://revoked.grc.com/">https://revoked.grc.com/</a>
      <br>
      <br>
      without squid, the browser shows that the certificate is revoked
      and doesn't show the page
      <br>
      with squid, the page is shown ...
      <br>
      <br>
      Thanks,
      <br>
      Walter
      <br>
    </blockquote>
    <br>
    I have solved it:<br>
    <br>
    my solution not only does certificate checks using OCSP, it also
    stores the real certificates into a different "database" folder;<br>
    if someone doesn't want this, just remove the few lines of the shell
    script;<br>
    as there exist no CA that allows IP adresses neither in certificate
    subject nor in the SAN (subject alternative name),<br>
    <br>
    <a class="moz-txt-link-freetext" href="https://www.whitehouse.gov/">https://www.whitehouse.gov/</a><br>
    (is blocked at my solution because of a root certificate not in the
    cert store)<br>
    <br>
    all these candidates are blocked with error  <br>
    <pre><i>X509_V_ERR_CERT_REJECTED</i></pre>
    it uses two components:<br>
    <br>
    - a shell script (BASH) called by the programme<br>
    - the main programme (in C): the only missing is an exception list
    of domains/hosts not to validate through this procedure<br>
    <br>
    the squid.conf is expanded by these lines:<br>
    <br>
    <squid.conf><br>
    acl certSelfSigned ssl_error X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT<br>
    acl certHasExpired ssl_error X509_V_ERR_CERT_HAS_EXPIRED<br>
    acl certNotValid ssl_error X509_V_ERR_CERT_NOT_YET_VALID<br>
    acl certRejected ssl_error X509_V_ERR_CERT_REJECTED<br>
    acl certRevoked ssl_error X509_V_ERR_CERT_REVOKED<br>
    acl certUntrusted ssl_error X509_V_ERR_CERT_UNTRUSTED<br>
    <br>
    acl certSelfSignedChain ssl_error
    X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN<br>
    acl certChainTooLong ssl_error X509_V_ERR_CERT_CHAIN_TOO_LONG<br>
    acl certPathLengthExceeded ssl_error X509_V_ERR_PATH_LENGTH_EXCEEDED<br>
    <br>
    acl certSignatureFailure ssl_error X509_V_ERR_CERT_SIGNATURE_FAILURE<br>
    acl crlSignatureFailure ssl_error X509_V_ERR_CRL_SIGNATURE_FAILURE<br>
    <br>
    acl caInvalid ssl_error X509_V_ERR_INVALID_CA<br>
    <br>
    acl squidDomainMismatch ssl_error SQUID_X509_V_ERR_DOMAIN_MISMATCH<br>
    acl squidInfiniteValidation ssl_error
    SQUID_X509_V_ERR_INFINITE_VALIDATION<br>
    acl squidSslHandshake ssl_error SQUID_ERR_SSL_HANDSHAKE<br>
    <br>
    sslproxy_cert_adapt setValidBefore all   ; I have these two, but
    they are not needed;<br>
    sslproxy_cert_adapt setValidAfter all<br>
    <br>
    sslproxy_cert_error deny certSelfSigned<br>
    sslproxy_cert_error deny certRejected<br>
    sslproxy_cert_error deny certRevoked<br>
    sslproxy_cert_error deny certHasExpired<br>
    sslproxy_cert_error deny certNotValid<br>
    sslproxy_cert_error deny certUntrusted<br>
    sslproxy_cert_error deny certSelfSignedChain<br>
    sslproxy_cert_error deny certChainTooLong<br>
    sslproxy_cert_error deny certPathLengthExceeded<br>
    sslproxy_cert_error deny certSignatureFailure<br>
    sslproxy_cert_error deny crlSignatureFailure<br>
    sslproxy_cert_error deny caInvalid<br>
    sslproxy_cert_error deny squidDomainMismatch<br>
    sslproxy_cert_error deny squidInfiniteValidation<br>
    sslproxy_cert_error deny squidSslHandshake<br>
    sslproxy_cert_error allow all<br>
    <br>
    sslcrtvalidator_program cache=8192 ttl=240
    /usr/lib64/squid/ssl_crtvalid/main.sh<br>
    sslcrtvalidator_children 12 startup=5 idle=1 concurrency=1<br>
    </squid.conf><br>
    <br>
    this main.sh script is only<br>
    <br>
    <main.sh><br>
    #!/bin/sh<br>
    /usr/lib64/squid/ssl_crtvalid/helper
    2>>/tmp/crtvalid-debug.log<br>
    </main.sh><br>
    when someone compiles the programme without _DEBUG<br>
    then the line in squid.conf would be without this<br>
    <br>
    sslcrtvalidator_program cache=8192 ttl=240
    /usr/lib64/squid/ssl_crtvalid/helper<br>
    <br>
    the shellscript  verify.sh is<br>
    <br>
    <verify.sh><br>
    #!/bin/sh<br>
    <br>
    CAFILE=/etc/pki/tls/certs/ca-bundle.trust.crt<br>
    DTABASE=/var/local/squid/ssl_crtvalid<br>
    <br>
    CERT=$1<br>
    CHAIN=$3<br>
    ISSUER=$2<br>
    SSLHOST=$4<br>
    <br>
    openssl verify -CAfile $CAFILE -untrusted $CHAIN $CERT<br>
    <br>
    OCSPURL=$(openssl x509 -in $CERT -noout -ocsp_uri)<br>
    <br>
    if [ "$OCSPURL" == "" ];<br>
    then<br>
      echo "$CERT: rejected"<br>
    else<br>
      OCSPHOST=$(echo "$OCSPURL" |gawk -F\/ '{ print $3 }' -)<br>
      openssl ocsp -CAfile $CAFILE -no_nonce -noverify -issuer $ISSUER
    -cert $CERT -url "$OCSPURL" -header Host $OCSPHOST |grep "$CERT" <br>
    fi<br>
    <br>
    FINGERPRINT=$(openssl x509 -in $CERT -noout -sha1 -fingerprint |sed
    "{s/SHA1\ Fingerprint\=//g;s/\://g}")<br>
    SUBJECT=$( openssl x509 -in $CERT -noout -subject |sed
    "{s/subject\=\ //g}")<br>
    <br>
    if [ -f $DTABASE/certs/$FINGERPRINT.pem ];<br>
    then<br>
      ENTRY=$(cat $DTABASE/index.txt |grep "$SSLHOST" |grep
    "$FINGERPRINT")<br>
      if [ "$ENTRY" == "" ];<br>
      then<br>
        echo -e -n "$SSLHOST\t$SUBJECT\t$FINGERPRINT.pem\n"
    >>$DTABASE/index.txt<br>
      fi<br>
    else<br>
      openssl x509 -in $CERT -out $DTABASE/certs/$FINGERPRINT.pem<br>
      echo -e -n "$SSLHOST\t$SUBJECT\t$FINGERPRINT.pem\n"
    >>$DTABASE/index.txt<br>
    fi<br>
    </verify.sh><br>
    <br>
    <helper.c><br>
    /*<br>
     * Squid SSL Validator helper programme<br>
     *<br>
     */<br>
    <br>
    #include <ctype.h><br>
    #include <fcntl.h><br>
    <br>
    #include <stdio.h><br>
    #include <stdlib.h><br>
    #include <string.h><br>
    <br>
    #include <time.h><br>
    <br>
    #include <unistd.h><br>
    <br>
    #define _DEBUG<br>
    <br>
    #ifdef _DEBUG<br>
    #define DEBUGINIT( ) debugInit( __LINE__ )<br>
    #define DEBUGOUT2( val, len ) debugWrite( (const void*) ( val ), len
    )<br>
    #define DEBUGOUT( szval ) debugWrite( (const void*) ( szval ),
    strlen( szval ) )<br>
    #define DEBUGOUTINT( intval ) debugOutputInt( __LINE__, #intval,
    intval )<br>
    #define DEBUGOUTSZ( szval ) debugOutputStr( __LINE__, #szval, szval
    )<br>
    #else<br>
    #define DEBUGINIT( )<br>
    #define DEBUGOUT2( val, len )<br>
    #define DEBUGOUT( szval )<br>
    #define DEBUGOUTINT( intval )<br>
    #define DEBUGOUTSZ( szval )<br>
    #endif<br>
    <br>
    enum _MSGTYPE { INTERNERROR = -1, NOERROR = 0, SSLERROR = 1 };<br>
    <br>
    struct _sslmsg_t<br>
    {<br>
        char szErrorName[ 72 ];<br>
        int nCertNmbr;<br>
    };<br>
    <br>
    const char szMsgConcurrencyRequired[ ] = "This SSL Certificate
    Validator helper is concurrent and requires the concurrency option
    to be specified.";<br>
    const char szMsgInvalidSize[ ] = "SSL Certificate Validator: invalid
    request size parameter.";<br>
    const char szMsgMemoryAllocFailed[ ] = "SSL Certificate Validator:
    memory allocation failed.";<br>
    const char szMsgSyntaxError[ ] = "SSL Certificate Validator: request
    syntax error.";<br>
    const char szMsgReadIOError[ ] = "SSL Certificate Validator: read
    i/o error.";<br>
    const char szMsgUnknownError[ ] = "SSL Certificate Validator:
    unknown error.";<br>
        <br>
    const char szSslMsgCertRevoked[ ] = "X509_V_ERR_CERT_REVOKED";<br>
    const char szSslMsgCertUntrusted[ ] = "X509_V_ERR_CERT_UNTRUSTED";<br>
    <br>
    const char szSslMsgCertRejected[ ] = "X509_V_ERR_CERT_REJECTED";<br>
    <br>
    const char szSslMsgCertHasExpired[ ] =
    "X509_V_ERR_CERT_HAS_EXPIRED";<br>
    const char szSslMsgCertNotYetValid[ ] =
    "X509_V_ERR_CERT_NOT_YET_VALID";<br>
    <br>
    const char szSslMsgCertChainTooLong[ ] =
    "X509_V_ERR_CERT_CHAIN_TOO_LONG";<br>
    <br>
    const char szSslMsgCertSelfSigned[ ] =
    "X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT";<br>
    <br>
    const char szSslMsgCertSelfSignedInChain[ ] =<br>
        "X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN";<br>
    <br>
    const char szSslMsgCertPathLengthExceeded[ ] =
    "X509_V_ERR_PATH_LENGTH_EXCEEDED";<br>
    <br>
    const char szSslMsgInvalidCa[ ] = "X509_V_ERR_INVALID_CA";<br>
    <br>
    const char szSslMsgSquidDomainMismatch[ ] =
    "SQUID_X509_V_ERR_DOMAIN_MISMATCH";<br>
    <br>
    const char* pszSslMsgs[ ] = { szSslMsgSquidDomainMismatch,<br>
        szSslMsgCertPathLengthExceeded,<br>
        szSslMsgCertSelfSigned,<br>
        szSslMsgCertSelfSignedInChain,<br>
        szSslMsgCertUntrusted,<br>
        szSslMsgCertRevoked,<br>
        szSslMsgCertHasExpired, szSslMsgCertNotYetValid };<br>
    <br>
    #ifdef _DEBUG<br>
    const char szDbgMarkInit[ ] = "=====[ INIT ]=====\n";<br>
    const char szDbgMarkReceiveRqustBegin[ ] = "-----[ REQUEST BEGIN
    ]-----\n";<br>
    const char szDbgMarkReceiveRqustEnd[ ] = "-----[ REQUEST END
    ]-----\n";<br>
    const char szDbgMarkReturnMsgBegin[ ] = "-----[ MSG BEGIN ]-----\n";<br>
    const char szDbgMarkReturnMsgEnd[ ] = "-----[ MSG END ]-----\n";<br>
    #endif<br>
    <br>
    <br>
    static int nFileCert;<br>
    static int nFileChain;<br>
    static int nFileIssuer;<br>
    <br>
    static char szFnameCert[ 260 ];<br>
    static char szFnameChain[ 260 ];<br>
    static char szFnameIssuer[ 260 ];<br>
    <br>
    static char szSslHost[ 260 ];<br>
    <br>
    static char* pszRqustBuf = (char*) NULL;<br>
    <br>
    static struct _sslmsg_t stRqustSslMsgs[ 8 ];<br>
    static int nRqustSslMsgsCount;<br>
    <br>
    <br>
    void cleanupData( void );<br>
    <br>
    void initData( void );<br>
    <br>
    int readRqustHlpr( int* pnEchoId, int* pnRqustRead );<br>
    int receiveRequest( int* pnEchoId );<br>
    <br>
    void returnMsg( int nEchoId, int nMsgType, int nCert, const char*
    pszMsg );<br>
    <br>
    int verifyCertificate( char* pszSslMsg );<br>
    int verifyHostName( const char* pszHostName );<br>
    <br>
    #ifdef _DEBUG<br>
    void debugInit( int nLine );<br>
    void debugOutputHlpr( int nLine, const void* pvdBuf, int nBufLen );<br>
    void debugOutputInt( int nLine, const char* pszName, int nVal );<br>
    void debugOutputStr( int nLine, const char* pszName, const char*
    pszVal );<br>
    void debugWrite( const void* pvdBuf, int nBufLen );<br>
    #endif<br>
    <br>
    <br>
    // call params: none<br>
    <br>
    int main( int argc, char* argv[ ] )<br>
    {<br>
        int nEchoId, nRet = 0;<br>
    <br>
        DEBUGINIT( );<br>
    <br>
        initData( );<br>
    <br>
        nRet = receiveRequest( &nEchoId );<br>
    <br>
        DEBUGOUTINT( nRet );<br>
    <br>
        if ( nRet < 0 )<br>
        {<br>
            switch ( nRet )<br>
            {<br>
                case -1 :<br>
                    returnMsg( -1, (int) INTERNERROR, -1,
    szMsgConcurrencyRequired );<br>
                    break;<br>
                case -2 :<br>
                    returnMsg( 0, (int) INTERNERROR, -1,
    szMsgMemoryAllocFailed );<br>
                    break;<br>
                case -3 :<br>
                    returnMsg( 0, (int) INTERNERROR, -1,
    szMsgInvalidSize );<br>
                    break;<br>
                case -4 :<br>
                    returnMsg( 0, (int) INTERNERROR, -1,
    szMsgSyntaxError );<br>
                    break;<br>
                case -5 :<br>
                    returnMsg( 0, (int) INTERNERROR, -1,
    szMsgReadIOError );<br>
                    break;<br>
                default :<br>
                    returnMsg( 0, (int) INTERNERROR, -1,
    szMsgUnknownError );<br>
            }<br>
            cleanupData( );<br>
            exit( EXIT_FAILURE );<br>
        }<br>
    <br>
        if ( nRet > 0 )<br>
        {<br>
            returnMsg( nEchoId, (int) NOERROR, 0, (const char*) NULL );<br>
            cleanupData( );<br>
            exit( EXIT_SUCCESS );<br>
        }<br>
    <br>
        {<br>
            int m, n;<br>
            for ( n = 0; n < sizeof( pszSslMsgs ) / sizeof( char* );
    n++ )<br>
                for ( m = 0; m < nRqustSslMsgsCount; m++ )<br>
                    if ( strcmp( pszSslMsgs[ n ], stRqustSslMsgs[ m
    ].szErrorName ) == 0 )<br>
                    {<br>
                        returnMsg( nEchoId, (int) SSLERROR,<br>
                            stRqustSslMsgs[ m ].nCertNmbr,<br>
                            stRqustSslMsgs[ m ].szErrorName );<br>
                        cleanupData( );<br>
                        exit( EXIT_SUCCESS );<br>
                    }<br>
        }<br>
    <br>
        if ( verifyHostName( szSslHost ) < 0 )<br>
        {<br>
            returnMsg( nEchoId, (int) SSLERROR, 0,
    szSslMsgSquidDomainMismatch );<br>
            cleanupData( );<br>
            exit( EXIT_SUCCESS );<br>
        }<br>
    <br>
        {<br>
            static char szSslMsg[ 72 ];<br>
            if ( ( nRet = verifyCertificate( szSslMsg ) ) < 0 )<br>
            {<br>
                returnMsg( nEchoId, (int) INTERNERROR, -1,
    szMsgUnknownError );<br>
                cleanupData( );<br>
                exit( EXIT_FAILURE );<br>
            }<br>
            if ( nRet > 0 )<br>
            {<br>
                returnMsg( nEchoId, (int) SSLERROR, 0, szSslMsg );<br>
                cleanupData( );<br>
                exit( EXIT_SUCCESS );<br>
            }<br>
        }<br>
        returnMsg( nEchoId, (int) NOERROR, 0, (const char*) NULL );<br>
        cleanupData( );<br>
        exit( EXIT_SUCCESS );<br>
    <br>
        return 0;<br>
    }<br>
    <br>
    void cleanupData( void )<br>
    {<br>
        if ( nFileCert > 0 )<br>
        {<br>
            unlink( szFnameCert );<br>
            nFileCert = 0;<br>
        }<br>
        if ( nFileChain > 0 )<br>
        {<br>
            unlink( szFnameChain );<br>
            nFileChain = 0;<br>
        }<br>
        if ( nFileIssuer > 0 )<br>
        {<br>
            unlink( szFnameIssuer );<br>
            nFileIssuer = 0;<br>
        }<br>
        if ( pszRqustBuf )<br>
        {<br>
            free( pszRqustBuf );<br>
            pszRqustBuf = (char*) NULL;<br>
        }<br>
        fsync( STDOUT_FILENO );<br>
    }<br>
    <br>
    void initData( void )<br>
    {<br>
        const char szFnameTmplte[ ] = "/tmp/squidXXXXXXXX";<br>
    <br>
        register int n;<br>
    <br>
        for ( n = 0; n < sizeof( stRqustSslMsgs ) / sizeof( struct
    _sslmsg_t ); n++ )<br>
        {<br>
            strcpy( stRqustSslMsgs[ n ].szErrorName, "" );<br>
            stRqustSslMsgs[ n ].nCertNmbr = 0;<br>
        }<br>
    <br>
        nRqustSslMsgsCount = 0;<br>
    <br>
        strcpy( szFnameCert, szFnameTmplte );    <br>
        strcpy( szFnameChain, szFnameTmplte );<br>
        strcpy( szFnameIssuer, szFnameTmplte );<br>
    <br>
        nFileCert = nFileChain = nFileIssuer = 0;<br>
    }<br>
    <br>
    int readRqustHlpr( int* pnEchoId, int* pnRqustRead )<br>
    {<br>
        const char chLf = '\n';<br>
    <br>
        static szBuf[ 260 ];<br>
    <br>
        int nLen, nCount = 0, nSize = 0, nRet = 0;<br>
    <br>
        if ( ( nLen = read( STDIN_FILENO, (void*) szBuf, 256 ) ) > 0
    )<br>
        {<br>
            char* pszNxt;<br>
    <br>
            szBuf[ nLen ] = '\0';<br>
    <br>
            DEBUGOUT( szDbgMarkReceiveRqustBegin );<br>
    <br>
            {<br>
                char* psz = (char*) szBuf;<br>
                long l = (long) strtol( psz, &pszNxt, 10 );<br>
                if ( psz < pszNxt )<br>
                {<br>
                    *pnEchoId = (int) l;<br>
                }<br>
                else<br>
                {<br>
                    nRet = -1;<br>
                }<br>
            }<br>
    <br>
            if ( nRet >= 0 )<br>
            {<br>
                char* psz = (char*) ++pszNxt;<br>
    <br>
                DEBUGOUT2( szBuf, nLen );<br>
    <br>
                if ( strncmp( psz, "cert_validate", 13 ) == 0 )<br>
                {<br>
                    long lVal = (long) strtol( psz + 14, &pszNxt, 10
    );<br>
                    if ( ( lVal > 0L ) && ( lVal < 10000L
    ) )<br>
                        nSize = (int) lVal;<br>
                    else<br>
                        *pnRqustRead = -1;<br>
    <br>
                    if ( nSize > 0 )<br>
                    {<br>
                        if ( pszRqustBuf = (char*) malloc( nSize + 4 ) )<br>
                        {<br>
                            int n = (int) strlen( ++pszNxt );<br>
    <br>
                            strcpy( pszRqustBuf, pszNxt );<br>
                            while ( ( n < nSize ) && ( ( nLen
    = read( STDIN_FILENO, (void*) ( pszRqustBuf + n ), nSize - n ) )
    > 0 ) )<br>
                            {<br>
                                *( pszRqustBuf + n + nLen ) = '\0';<br>
    <br>
                                DEBUGOUT2( pszRqustBuf + n, nLen );<br>
                                nCount++;<br>
                                n += nLen;<br>
                            }<br>
                            DEBUGOUT2( &chLf, 1 );<br>
    <br>
                            if ( n >= nSize )<br>
                                *pnRqustRead = 1;<br>
                            else<br>
                                nRet = -5;<br>
                        }<br>
                        else<br>
                            nRet = -2;<br>
                    }<br>
                    else<br>
                        nRet = -3;<br>
                }<br>
                else<br>
                    nRet = -4;<br>
            }<br>
    <br>
            DEBUGOUT( szDbgMarkReceiveRqustEnd );<br>
        }<br>
        else<br>
            nRet = -5;<br>
    <br>
        DEBUGOUTINT( nRet );<br>
        DEBUGOUTINT( nSize );<br>
        DEBUGOUTINT( nCount );<br>
    <br>
        return nRet;<br>
    }<br>
    <br>
    int receiveRequest( int* pnEchoId )<br>
    {<br>
        const char chLf = '\n';<br>
    <br>
        static char sz[ 130 ], szTmp[ 50 ];<br>
    <br>
        char* pszItemPtr;<br>
    <br>
        int m, n, nItemLen, nRqustRead = 0;<br>
    <br>
        int nRet = (int) readRqustHlpr( pnEchoId, &nRqustRead );<br>
    <br>
        DEBUGOUTINT( nRqustRead );<br>
    <br>
        if ( nRet < 0 )<br>
            return nRet;<br>
    <br>
        if ( nRet == 0 )<br>
        {<br>
            if ( pszItemPtr = strstr( pszRqustBuf, "host=" ) )<br>
            {<br>
                nItemLen = strcspn( pszItemPtr += 5, " \r\n" );<br>
                strncpy( szSslHost, pszItemPtr, nItemLen );<br>
                szSslHost[ nItemLen ] = '\0';<br>
            }<br>
            else<br>
                nRet = 1;<br>
        }<br>
    <br>
        DEBUGOUTINT( nRet );<br>
    <br>
        if ( nRet > 0 )<br>
            return nRet;<br>
    <br>
        DEBUGOUTSZ( szSslHost );<br>
    <br>
        if ( nRet == 0 )<br>
        {<br>
            for ( n = 0; n < 8; n++ )<br>
            {<br>
                int nCertNmbr = -1;<br>
    <br>
                sprintf( sz, "error_cert_%d=", n );<br>
                if ( pszItemPtr = strstr( pszRqustBuf, sz ) )<br>
                {<br>
                    nItemLen = strcspn( pszItemPtr += 13, " \r\n" );<br>
                    strncpy( szTmp, (void*) pszItemPtr, nItemLen );<br>
                    szTmp[ nItemLen ] = '\0';<br>
    <br>
                    for ( m = 0; m < 7; m++ )<br>
                    {<br>
                        sprintf( sz, "cert_%d", m );<br>
                        if ( strcmp( sz, szTmp ) == 0 )<br>
                        {<br>
                            nCertNmbr = m;<br>
                            break;<br>
                        }<br>
                    }<br>
                }<br>
                if ( nCertNmbr >= 0 )<br>
                {<br>
                    sprintf( sz, "error_name_%d=", n );<br>
                    if ( pszItemPtr = strstr( pszRqustBuf, sz ) )<br>
                    {<br>
                        nItemLen = strcspn( pszItemPtr += 13, " \r\n" );<br>
                        strncpy( szTmp, (void*) pszItemPtr, nItemLen );<br>
                        szTmp[ nItemLen ] = '\0';<br>
                        strcpy( stRqustSslMsgs[ nRqustSslMsgsCount
    ].szErrorName, szTmp );<br>
                        stRqustSslMsgs[ nRqustSslMsgsCount++ ].nCertNmbr
    = nCertNmbr;<br>
                    }<br>
                    else<br>
                        nRet = 1;<br>
                }<br>
            }<br>
        }<br>
    <br>
        DEBUGOUTINT( nRet );<br>
    <br>
        if ( nRet > 0 )<br>
            return nRet;<br>
    <br>
        DEBUGOUTINT( nRqustSslMsgsCount );<br>
    #ifdef _DEBUG<br>
        for ( n = 0; n < nRqustSslMsgsCount; n++ )<br>
        {<br>
            DEBUGOUTINT( stRqustSslMsgs[ n ].nCertNmbr );<br>
            DEBUGOUTSZ( stRqustSslMsgs[ n ].szErrorName );<br>
        }<br>
    #endif<br>
    <br>
        if ( nRet == 0 )<br>
        {<br>
            if ( ( nFileCert = mkstemp( szFnameCert ) ) > 0 );<br>
            else<br>
            {<br>
                nRet = 2;<br>
            }<br>
            if ( nRet == 0 )<br>
            {<br>
                if ( ( nFileChain = mkstemp( szFnameChain ) ) > 0 );<br>
                else<br>
                {<br>
                    close( nFileCert );<br>
                    unlink( szFnameCert );<br>
                    nFileCert = 0;<br>
                    nRet = 2;<br>
                }<br>
            }<br>
            if ( nRet == 0 )<br>
            {<br>
                if ( ( nFileIssuer = mkstemp( szFnameIssuer ) ) > 0
    );<br>
                else<br>
                {<br>
                    close( nFileCert );<br>
                    close( nFileChain );<br>
                    unlink( szFnameCert );<br>
                    unlink( szFnameChain );<br>
                    nFileCert = 0;<br>
                    nFileChain = 0;<br>
                    nRet = 2;<br>
                }<br>
            }<br>
        }<br>
    <br>
        DEBUGOUTINT( nRet );<br>
    <br>
        if ( nRet > 0 )<br>
            return nRet;<br>
        <br>
        DEBUGOUTINT( nFileCert );<br>
        DEBUGOUTINT( nFileChain );<br>
        DEBUGOUTINT( nFileIssuer );<br>
    <br>
        if ( nRet == 0 )<br>
        {<br>
            for ( n = 0; n < 8; n++ )<br>
            {<br>
                sprintf( sz, "cert_%d=-----BEGIN CERTIFICATE-----", n );<br>
                if ( pszItemPtr = strstr( pszRqustBuf, sz ) )<br>
                {<br>
                    char* pszTag = (char*) strstr( pszItemPtr += 7,
    "-----END CERTIFICATE-----" );<br>
                    if ( pszTag )<br>
                    {<br>
                        nItemLen = (int) ( pszTag - pszItemPtr ) + 25;<br>
                        if ( n == 0 )<br>
                        {<br>
                            write( nFileCert, (void*) pszItemPtr,
    nItemLen );<br>
                            write( nFileCert, (void*) &chLf, 1 );<br>
                        }<br>
                        if ( n == 1 )<br>
                        {<br>
                            write( nFileIssuer, (void*) pszItemPtr,
    nItemLen );<br>
                            write( nFileIssuer, (void*) &chLf, 1 );<br>
                        }<br>
                        if ( n >= 1 )<br>
                        {<br>
                            write( nFileChain, (void*) pszItemPtr,
    nItemLen );<br>
                            write( nFileChain, (void*) &chLf, 1 );<br>
                        }<br>
                    }<br>
                    else<br>
                    {<br>
                        nRet = 3;<br>
                        break;<br>
                    }<br>
                }<br>
                else<br>
                {<br>
                    if ( n == 0 )<br>
                        nRet = 3;<br>
                    break;<br>
                }<br>
            }<br>
    <br>
            close( nFileCert );<br>
            close( nFileChain );<br>
            close( nFileIssuer );<br>
        }<br>
    <br>
        DEBUGOUTINT( nRet );<br>
    <br>
        DEBUGOUTSZ( szFnameCert );<br>
        DEBUGOUTSZ( szFnameChain );<br>
        DEBUGOUTSZ( szFnameIssuer );<br>
    <br>
        return nRet;<br>
    }<br>
    <br>
    void returnMsg( int nEchoId, int nMsgType, int nCert, const char*
    pszMsg )<br>
    {<br>
        static char sz[ 260 ];<br>
        static char szMsgBuf[ 260 ];<br>
    <br>
    #ifdef _DEBUG<br>
        const char szEndTerm[ ] = "\\x01\n";<br>
    #endif<br>
    <br>
        if ( nMsgType == (int) NOERROR )<br>
        {<br>
            sprintf( szMsgBuf, "%d OK 0 \1", nEchoId );<br>
        }<br>
        else<br>
        {<br>
            if ( nMsgType == (int) SSLERROR )<br>
            {<br>
                const char szFmtError[ ] = "error_name_0=%s\n"<br>
                    "error_reason_0=Checked by "<br>
                        "Squid SSL Certificate Validator\n"<br>
                    "error_cert_0=cert_%d\n";<br>
    <br>
                sprintf( sz, szFmtError, pszMsg, nCert );<br>
    <br>
                sprintf( szMsgBuf, "%d ERR %d %s\1", nEchoId,<br>
                    strlen( sz ), sz );<br>
            }<br>
            else<br>
            {<br>
                const char szFmtMessage[ ] = "message=\"%s\"";<br>
    <br>
                sprintf( sz, szFmtMessage, pszMsg );<br>
    <br>
                if ( nEchoId >= 0 )<br>
                    sprintf( szMsgBuf, "%d BH %s\1", nEchoId, sz );<br>
                else<br>
                    sprintf( szMsgBuf, "BH %s\1", sz );<br>
            }<br>
        }<br>
    <br>
        write( STDOUT_FILENO, (void*) szMsgBuf, strlen( szMsgBuf ) );<br>
    <br>
        DEBUGOUTINT( nMsgType );<br>
        DEBUGOUTINT( nCert );<br>
    <br>
        DEBUGOUT( szDbgMarkReturnMsgBegin );<br>
        DEBUGOUT2( szMsgBuf, strlen( szMsgBuf ) - 1 );<br>
        DEBUGOUT2( szEndTerm, strlen( szEndTerm ) );<br>
        DEBUGOUT( szDbgMarkReturnMsgEnd );<br>
    }<br>
    <br>
    int verifyCertificate( char* pszSslMsg )<br>
    {<br>
        static char szGrabStdOut[ 4100 ];<br>
        static char szGrabStdErr[ 4100 ];<br>
    <br>
        int pipefdin[ 2 ];<br>
        int pipefdout[ 2 ];<br>
        int pipefderr[ 2 ];<br>
    <br>
        pid_t cpid;<br>
    <br>
        if ( pipe( pipefdin ) == -1 )<br>
            goto failPipeIn;<br>
    <br>
        DEBUGOUTINT( pipefdin[ 0 ] );<br>
        DEBUGOUTINT( pipefdin[ 1 ] );<br>
    <br>
        if ( pipe( pipefdout ) == -1 )<br>
            goto failPipeOut;<br>
    <br>
        DEBUGOUTINT( pipefdout[ 0 ] );<br>
        DEBUGOUTINT( pipefdout[ 1 ] );<br>
    <br>
        if ( pipe( pipefderr ) == -1 )<br>
            goto failPipeErr;<br>
    <br>
        DEBUGOUTINT( pipefderr[ 0 ] );<br>
        DEBUGOUTINT( pipefderr[ 1 ] );<br>
    <br>
        cpid = fork( );<br>
        if ( cpid == -1 )<br>
            goto failFork;<br>
    <br>
        DEBUGOUTINT( cpid );<br>
    <br>
        if ( cpid == 0 )<br>
        {                /* inside child fork */<br>
            close( pipefdin[ 1 ] );<br>
            close( pipefdout[ 0 ] );<br>
            close( pipefderr[ 0 ] );<br>
    <br>
            dup2( pipefdin[ 0 ], STDIN_FILENO );<br>
            close( pipefdin[ 0 ] );<br>
    <br>
            dup2( pipefdout[ 1 ], STDOUT_FILENO );<br>
            close( pipefdout[ 1 ] );<br>
    <br>
            dup2( pipefderr[ 1 ], STDERR_FILENO );<br>
            close( pipefderr[ 1 ] );<br>
    <br>
            if ( execl( "/usr/lib64/squid/ssl_crtvalid/verify.sh",
    "./verify.sh",<br>
                szFnameCert, szFnameIssuer, szFnameChain, szSslHost,<br>
                (char*) NULL ) == -1 )<br>
            {<br>
                exit( EXIT_FAILURE );<br>
            }<br>
        }<br>
        else<br>
        {                /* inside parent fork */<br>
            char* psz;<br>
            int n;<br>
    <br>
            close( pipefdin[ 0 ] );<br>
            close( pipefdout[ 1 ] );<br>
            close( pipefderr[ 1 ] );<br>
    <br>
            close( pipefdin[ 1 ] );<br>
    <br>
            n = 0, psz = szGrabStdOut;<br>
            while ( ( n++ < 4096 ) && ( read( pipefdout[ 0 ],
    psz++, 1 ) > 0 ) )<br>
                *psz = '\0';<br>
    <br>
            n = 0, psz = szGrabStdErr;<br>
            while ( ( n++ < 4096 ) && ( read( pipefderr[ 0 ],
    psz++, 1 ) > 0 ) )<br>
                *psz = '\0';<br>
    <br>
            close( pipefdout[ 0 ] );<br>
            close( pipefderr[ 0 ] );<br>
    <br>
            wait( NULL );<br>
        }<br>
    <br>
        /* this is only parent fork */<br>
    <br>
        DEBUGOUTSZ( szGrabStdOut );<br>
        DEBUGOUTSZ( szGrabStdErr );<br>
    <br>
        {<br>
            static char sz[ 260 ];<br>
    <br>
            char* psz = (char*) szGrabStdOut;<br>
    <br>
            sprintf( sz, "%s: OK", szFnameCert );<br>
            if ( strncmp( psz, sz, strlen( sz ) ) == 0 )<br>
            {<br>
                psz += strlen( sz ) + 1;<br>
    <br>
                sprintf( sz, "%s: revoked", szFnameCert );<br>
                if ( strncmp( psz, sz, strlen( sz ) ) == 0 )<br>
                {<br>
                    strcpy( pszSslMsg, szSslMsgCertRevoked );<br>
                    return 1;<br>
                }<br>
    <br>
                sprintf( sz, "%s: good", szFnameCert );<br>
                if ( strncmp( psz, sz, strlen( sz ) ) == 0 );<br>
                else<br>
                    goto invalidCert;<br>
            }<br>
            else<br>
            {<br>
    invalidCert:<br>
                strcpy( pszSslMsg, szSslMsgCertRejected );<br>
                return 1;<br>
            }<br>
        }<br>
    <br>
        return 0;<br>
    <br>
    failFork:<br>
        close( pipefderr[ 0 ] );<br>
        close( pipefderr[ 1 ] );    <br>
    failPipeErr:<br>
        close( pipefdout[ 0 ] );<br>
        close( pipefdout[ 1 ] );<br>
    failPipeOut:<br>
        close( pipefdin[ 0 ] );<br>
        close( pipefdin[ 1 ] );<br>
    failPipeIn:<br>
        return -1;<br>
    }<br>
    <br>
    int verifyHostName( const char* pszHostName )<br>
    {<br>
        int nLen = (int) strlen( pszHostName );<br>
        char* psz = (char*) ( pszHostName + nLen - 1 );<br>
    <br>
        if ( strspn( pszHostName, "0123456789." ) == nLen )<br>
            return -1;<br>
    <br>
        if ( strspn( pszHostName,
    "0123456789abcdefghijklmnopqrstuvwxyz.-" ) < nLen )<br>
            return -1;<br>
    <br>
        if ( *psz == ']' )<br>
            return -1;<br>
    <br>
        if ( isdigit( (int) *psz ) )<br>
            return -1;<br>
    }<br>
    <br>
    <br>
    #ifdef _DEBUG<br>
    void debugInit( int nLine )<br>
    {<br>
        static char sz[ 260 ];<br>
    <br>
        time_t t = time( (time_t*) NULL );<br>
    <br>
        debugWrite( (const void*) szDbgMarkInit, strlen( szDbgMarkInit )
    );<br>
    <br>
        strftime( sz, 80, "date/time: %a, %d-%b-%Y; %H:%M:%S\n",
    localtime( &t ) );<br>
        debugOutputHlpr( nLine, (const void*) sz, strlen( sz ) );<br>
    }<br>
    <br>
    void debugOutputHlpr( int nLine, const void* pvdBuf, int nBufLen )<br>
    {<br>
        static char sz[ 130 ];<br>
        <br>
        pid_t pid = (pid_t) getpid( );<br>
        <br>
        sprintf( sz, "ssl_crtvalid/helper[pid=%d,line=%d] ", (int) pid,
    (int) nLine );<br>
    <br>
        debugWrite( (const void*) sz, strlen( sz ) );<br>
        debugWrite( pvdBuf, nBufLen );<br>
    }<br>
    <br>
    void debugOutputInt( int nLine, const char* pszName, int nVal )<br>
    {<br>
        static char sz[ 260 ];<br>
        sprintf( sz, "%s: %d\n", pszName, nVal );<br>
        debugOutputHlpr( nLine, (const void*) sz, strlen( sz ) );<br>
    }<br>
    <br>
    void debugOutputStr( int nLine, const char* pszName, const char*
    pszVal )<br>
    {<br>
        static char sz[ 260 ];<br>
        sprintf( sz, "%s: '%s'\n", pszName, pszVal );<br>
        debugOutputHlpr( nLine, (const void*) sz, strlen( sz ) );<br>
    }<br>
    <br>
    void debugWrite( const void* pvdBuf, int nBufLen )<br>
    {<br>
        write( STDERR_FILENO, pvdBuf, nBufLen );<br>
    }<br>
    #endif<br>
    </helper.c><br>
  </body>
</html>