#include <Security/SecureTransport.h>
#include <Security/SecureTransportPriv.h>
#include <Security/Security.h>
#include <clAppUtils/sslAppUtils.h>
#include <clAppUtils/ioSock.h>
#include <utilLib/common.h>
#include <CoreServices/../Frameworks/CarbonCore.framework/Headers/MacErrors.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <time.h>
#include <ctype.h>
#include <sys/param.h>
static void usage(char **argv)
{
printf("Usage: %s [options]\n", argv[0]);
printf("options:\n");
printf(" -t testNum -- only do test testNum; default is all\n");
printf(" -q -- quiet\n");
printf(" -b -- non blocking I/O\n");
printf(" -p -- pause for malloc debug\n");
exit(1);
}
#define IGNORE_SIGPIPE 1
#if IGNORE_SIGPIPE
#include <signal.h>
void sigpipe(int sig)
{
}
#endif
typedef struct {
const char *hostName;
int port;
SSLCipherSuite cipherSuite;
SSL_ECDSA_NamedCurve specCurve;
SSL_ECDSA_NamedCurve expCurve;
const char *keychain;
const char *kcPassword;
} EcdsaTestParams;
static const EcdsaTestParams ecdsaTestParams[] =
{
{
"tls.secg.org", 8443, TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA,
SSL_Curve_None, SSL_Curve_None,
"ecdsa.keychain", "password"
},
{
"tls.secg.org", 40023, TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,
SSL_Curve_None, SSL_Curve_secp256r1
},
{
"tls.secg.org", 40023, TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,
SSL_Curve_secp256r1, SSL_Curve_secp256r1
},
{
"tls.secg.org", 40023, TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA,
SSL_Curve_None, SSL_Curve_secp256r1
},
{
"tls.secg.org", 40023, TLS_ECDHE_ECDSA_WITH_RC4_128_SHA,
SSL_Curve_None, SSL_Curve_secp256r1
},
{
"tls.secg.org", 40023, TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA,
SSL_Curve_None, SSL_Curve_secp256r1
},
{
"tls.secg.org", 40023, TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA,
SSL_Curve_None, SSL_Curve_secp256r1
},
{
"tls.secg.org", 40023, TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA,
SSL_Curve_None, SSL_Curve_secp256r1
},
{
"tls.secg.org", 40023, TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA,
SSL_Curve_secp256r1, SSL_Curve_secp256r1
},
{
"tls.secg.org", 40023, TLS_ECDH_ECDSA_WITH_RC4_128_SHA,
SSL_Curve_None, SSL_Curve_secp256r1
},
{
"tls.secg.org", 40023, TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA,
SSL_Curve_None, SSL_Curve_secp256r1
},
{
"tls.secg.org", 40023, TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA,
SSL_Curve_secp256r1, SSL_Curve_secp256r1
},
{
"tls.secg.org", 40024, TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,
SSL_Curve_None, SSL_Curve_secp384r1
},
{
"tls.secg.org", 40024, TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA,
SSL_Curve_None, SSL_Curve_secp384r1
},
{
"tls.secg.org", 40024, TLS_ECDHE_ECDSA_WITH_RC4_128_SHA,
SSL_Curve_None, SSL_Curve_secp384r1
},
{
"tls.secg.org", 40024, TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA,
SSL_Curve_None, SSL_Curve_secp384r1
},
{
"tls.secg.org", 40024, TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA,
SSL_Curve_None, SSL_Curve_secp384r1
},
{
"tls.secg.org", 40024, TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA,
SSL_Curve_None, SSL_Curve_secp384r1
},
{
"tls.secg.org", 40024, TLS_ECDH_ECDSA_WITH_RC4_128_SHA,
SSL_Curve_None, SSL_Curve_secp384r1
},
{
"tls.secg.org", 40024, TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA,
SSL_Curve_None, SSL_Curve_secp384r1
},
{
"tls.secg.org", 40025, TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,
SSL_Curve_None, SSL_Curve_secp521r1
},
{
"tls.secg.org", 40025, TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA,
SSL_Curve_None, SSL_Curve_secp521r1
},
{
"tls.secg.org", 40025, TLS_ECDHE_ECDSA_WITH_RC4_128_SHA,
SSL_Curve_None, SSL_Curve_secp521r1
},
{
"tls.secg.org", 40025, TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA,
SSL_Curve_None, SSL_Curve_secp521r1
},
{
"tls.secg.org", 40025, TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA,
SSL_Curve_None, SSL_Curve_secp521r1
},
{
"tls.secg.org", 40025, TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA,
SSL_Curve_None, SSL_Curve_secp521r1
},
{
"tls.secg.org", 40025, TLS_ECDH_ECDSA_WITH_RC4_128_SHA,
SSL_Curve_None, SSL_Curve_secp521r1
},
{
"tls.secg.org", 40025, TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA,
SSL_Curve_None, SSL_Curve_secp521r1
},
{
"ecc.fedora.redhat.com", 8443, TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,
SSL_Curve_None, SSL_Curve_secp256r1
},
{
"ecc.fedora.redhat.com", 8443, TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA,
SSL_Curve_secp256r1, SSL_Curve_secp256r1
},
{
"ecc.fedora.redhat.com", 8443, TLS_ECDHE_ECDSA_WITH_RC4_128_SHA,
SSL_Curve_None, SSL_Curve_secp256r1
},
{
"ecc.fedora.redhat.com", 8443, TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA,
SSL_Curve_secp256r1, SSL_Curve_secp256r1
},
{
"ecc.fedora.redhat.com", 8443, TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA,
SSL_Curve_secp256r1, SSL_Curve_secp256r1
},
{
"ecc.fedora.redhat.com", 8443, TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA,
SSL_Curve_None, SSL_Curve_secp256r1
},
{
"ecc.fedora.redhat.com", 8443, TLS_ECDH_ECDSA_WITH_RC4_128_SHA,
SSL_Curve_secp256r1, SSL_Curve_secp256r1
},
{
"ecc.fedora.redhat.com", 8443, TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA,
SSL_Curve_secp256r1, SSL_Curve_secp256r1
},
{
"ecc.fedora.redhat.com", 8445, TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA,
SSL_Curve_None, SSL_Curve_secp521r1
},
{
"ecc.fedora.redhat.com", 8444, TLS_ECDHE_ECDSA_WITH_RC4_128_SHA,
SSL_Curve_secp384r1, SSL_Curve_secp384r1
},
{
"ecc.fedora.redhat.com", 8444, TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA,
SSL_Curve_secp384r1, SSL_Curve_secp384r1
},
{
"ecc.fedora.redhat.com", 8444, TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA,
SSL_Curve_None, SSL_Curve_secp384r1
},
{
"ecc.fedora.redhat.com", 8444, TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA,
SSL_Curve_None, SSL_Curve_secp384r1
},
{
"ecc.fedora.redhat.com", 8444, TLS_ECDH_ECDSA_WITH_RC4_128_SHA,
SSL_Curve_secp384r1, SSL_Curve_secp384r1
},
{
"ecc.fedora.redhat.com", 8444, TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA,
SSL_Curve_secp384r1, SSL_Curve_secp384r1
},
{
"ecc.fedora.redhat.com", 8445, TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA,
SSL_Curve_None, SSL_Curve_secp521r1
},
{
"ecc.fedora.redhat.com", 8445, TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA,
SSL_Curve_secp521r1, SSL_Curve_secp521r1
},
{
"ecc.fedora.redhat.com", 8445, TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA,
SSL_Curve_secp521r1, SSL_Curve_secp521r1
},
{
"ecc.fedora.redhat.com", 443, TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
SSL_Curve_secp256r1, SSL_Curve_secp256r1
},
{
"ecc.fedora.redhat.com", 443, TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,
SSL_Curve_secp256r1, SSL_Curve_secp256r1
},
{
"ecc.fedora.redhat.com", 443, TLS_ECDHE_RSA_WITH_RC4_128_SHA,
SSL_Curve_secp256r1, SSL_Curve_secp256r1
},
{
"ecc.fedora.redhat.com", 443, TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA,
SSL_Curve_secp256r1, SSL_Curve_secp256r1
},
{
"ecc.fedora.redhat.com", 443, TLS_ECDH_RSA_WITH_AES_128_CBC_SHA,
SSL_Curve_None, SSL_Curve_secp256r1
},
{
"ecc.fedora.redhat.com", 443, TLS_ECDH_RSA_WITH_AES_256_CBC_SHA,
SSL_Curve_secp256r1, SSL_Curve_secp256r1
},
{
"ecc.fedora.redhat.com", 443, TLS_ECDH_RSA_WITH_RC4_128_SHA,
SSL_Curve_None, SSL_Curve_secp256r1
},
{
"ecc.fedora.redhat.com", 443, TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA,
SSL_Curve_None, SSL_Curve_secp256r1
},
};
#define NUM_TEST_PARAMS (sizeof(ecdsaTestParams) / sizeof(ecdsaTestParams[0]))
static void dumpParams(
const EcdsaTestParams *testParams)
{
printf("%s:%d %-33s ",
testParams->hostName, testParams->port,
sslGetCipherSuiteString(testParams->cipherSuite)+4);
if(testParams->expCurve != SSL_Curve_None) {
printf("expCurve = %s ", sslCurveString(testParams->expCurve));
}
if(testParams->specCurve != SSL_Curve_None) {
printf("specCurve = %s ", sslCurveString(testParams->specCurve));
}
if(testParams->keychain) {
printf("Client Auth Enabled");
}
putchar('\n');
}
static void dumpErrInfo(
const char *op,
const EcdsaTestParams *testParams,
OSStatus ortn)
{
printf("***%s failed for ", op);
dumpParams(testParams);
printf(" error: %s\n", sslGetSSLErrString(ortn));
}
#define RCV_BUF_SIZE 256
static int doSslPing(
const EcdsaTestParams *testParams,
bool quiet,
int nonBlocking)
{
PeerSpec peerId;
otSocket sock = 0;
OSStatus ortn;
SSLContextRef ctx = NULL;
SSLCipherSuite negCipher;
ortn = MakeServerConnection(testParams->hostName, testParams->port,
nonBlocking, &sock, &peerId);
if(ortn) {
printf("MakeServerConnection(%s) returned %d\n",
testParams->hostName, (int)ortn);
return -1;
}
ortn = SSLNewContext(false, &ctx);
if(ortn) {
printSslErrStr("SSLNewContext", ortn);
goto cleanup;
}
ortn = SSLSetIOFuncs(ctx, SocketRead, SocketWrite);
if(ortn) {
printSslErrStr("SSLSetIOFuncs", ortn);
goto cleanup;
}
ortn = SSLSetProtocolVersionEnabled(ctx, kSSLProtocolAll, false);
if(ortn) {
printSslErrStr("SSLSetProtocolVersionEnabled", ortn);
goto cleanup;
}
ortn = SSLSetProtocolVersionEnabled(ctx, kTLSProtocol1, true);
if(ortn) {
printSslErrStr("SSLSetProtocolVersionEnabled", ortn);
goto cleanup;
}
ortn = SSLSetEnabledCiphers(ctx, &testParams->cipherSuite, 1);
if(ortn) {
printSslErrStr("SSLSetEnabledCiphers", ortn);
goto cleanup;
}
ortn = SSLSetConnection(ctx, (SSLConnectionRef)sock);
if(ortn) {
printSslErrStr("SSLSetConnection", ortn);
goto cleanup;
}
ortn = SSLSetAllowsExpiredCerts(ctx, true);
if(ortn) {
printSslErrStr("SSLSetAllowExpiredCerts", ortn);
goto cleanup;
}
ortn = SSLSetAllowsAnyRoot(ctx, true);
if(ortn) {
printSslErrStr("SSLSetAllowAnyRoot", ortn);
goto cleanup;
}
if(testParams->specCurve != SSL_Curve_None) {
ortn = SSLSetECDSACurves(ctx, &testParams->specCurve, 1);
if(ortn) {
printSslErrStr("SSLSetAllowAnyRoot", ortn);
goto cleanup;
}
}
if(testParams->keychain) {
char kcPath[2000];
const char *lbd = getenv("LOCAL_BUILD_DIR");
if(lbd == NULL) {
printf("WARNING: no LOCAL_BUILD_DIR env var faound\n");
lbd = "";
}
snprintf(kcPath, 2000, "%s/%s", lbd, testParams->keychain);
SecKeychainRef kcRef = NULL;
CFArrayRef certArray = getSslCerts(kcPath,
CSSM_FALSE, CSSM_FALSE, NULL, &kcRef);
if(kcRef) {
ortn = SecKeychainUnlock(kcRef,
strlen(testParams->kcPassword), testParams->kcPassword,
true);
if(ortn) {
cssmPerror("SecKeychainUnlock", ortn);
}
CFRelease(kcRef);
}
if(certArray == NULL) {
printf("***WARNING no keychain found at %s\n", kcPath);
}
ortn = SSLSetCertificate(ctx, certArray);
if(ortn) {
printSslErrStr("SSLSetAllowAnyRoot", ortn);
goto cleanup;
}
CFRelease(certArray);
}
do {
ortn = SSLHandshake(ctx);
} while (ortn == errSSLWouldBlock);
switch(ortn) {
case noErr:
break;
case errSSLClosedGraceful:
case errSSLClosedNoNotify:
ortn = noErr;
break;
default:
dumpErrInfo("SSLHandshake", testParams, ortn);
goto cleanup;
}
ortn = SSLGetNegotiatedCipher(ctx, &negCipher);
if(ortn) {
dumpErrInfo("SSLHandshake", testParams, ortn);
goto cleanup;
}
if(negCipher != testParams->cipherSuite) {
printf("***Cipher mismatch for ");
dumpParams(testParams);
printf("Negotiated cipher: %s\n", sslGetCipherSuiteString(negCipher));
ortn = ioErr;
goto cleanup;
}
if(testParams->expCurve != SSL_Curve_None) {
SSL_ECDSA_NamedCurve actNegCurve;
ortn = SSLGetNegotiatedCurve(ctx, &actNegCurve);
if(ortn) {
printSslErrStr("SSLGetNegotiatedCurve", ortn);
goto cleanup;
}
if(actNegCurve != testParams->expCurve) {
printf("***Negotiated curve error\n");
printf("Specified curve: %s\n", sslCurveString(testParams->specCurve));
printf("Expected curve: %s\n", sslCurveString(testParams->expCurve));
printf("Obtained curve: %s\n", sslCurveString(actNegCurve));
ortn = ioErr;
goto cleanup;
}
}
if(testParams->keychain) {
SSLClientCertificateState authState;
ortn = SSLGetClientCertificateState(ctx, &authState);
if(ortn) {
printSslErrStr("SSLGetClientCertificateState", ortn);
goto cleanup;
}
if(authState != kSSLClientCertSent) {
printf("***Unexpected ClientCertificateState\n");
printf(" Expected: ClientCertSent\n");
printf(" Received: %s\n", sslGetClientCertStateString(authState));
ortn = ioErr;
goto cleanup;
}
}
ortn = SSLClose(ctx);
cleanup:
if(sock) {
endpointShutdown(sock);
}
if(ctx) {
SSLDisposeContext(ctx);
}
return (int)ortn;
}
int main(int argc, char **argv)
{
int ourRtn = 0;
bool quiet = false;
int nonBlocking = false;
unsigned minDex = 0;
unsigned maxDex = NUM_TEST_PARAMS-1;
bool doPause = false;
extern char *optarg;
int arg;
while ((arg = getopt(argc, argv, "t:bpqh")) != -1) {
switch (arg) {
case 't':
minDex = maxDex = atoi(optarg);
if(minDex > (NUM_TEST_PARAMS - 1)) {
printf("***max test number is %u.\n", (unsigned)NUM_TEST_PARAMS);
exit(1);
}
break;
case 'q':
quiet = true;
break;
case 'b':
nonBlocking = true;
break;
case 'p':
doPause = true;
break;
default:
usage(argv);
}
}
if(optind != argc) {
usage(argv);
}
#if IGNORE_SIGPIPE
signal(SIGPIPE, sigpipe);
#endif
testStartBanner("sslEcdsa", argc, argv);
if(doPause) {
fpurge(stdin);
printf("Pausing at top of loop; CR to continue: ");
fflush(stdout);
getchar();
}
for(unsigned dex=minDex; dex<=maxDex; dex++) {
const EcdsaTestParams *testParams = &ecdsaTestParams[dex];
if(!quiet) {
printf("[%u]: ", dex);
dumpParams(testParams);
}
ourRtn = doSslPing(testParams, quiet, nonBlocking);
if(ourRtn) {
if(testError(quiet)) {
break;
}
}
}
if(doPause) {
fpurge(stdin);
printf("Pausing at end of loop; CR to continue: ");
fflush(stdout);
getchar();
}
if(!quiet) {
if(ourRtn == 0) {
printf("===== sslEcdsa test PASSED =====\n");
}
else {
printf("****sslEcdsa test FAILED\n");
}
}
return ourRtn;
}