<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>