--- /dev/null
+/*
+ * Copyright (c) 2006-2008,2010-2014 Apple Inc. All Rights Reserved.
+ */
+
+#include "sslAppUtils.h"
+#include "fileIo.h"
+#include <stdlib.h>
+#include <stdio.h>
+#include <sys/param.h>
+#include <Security/SecBase.h>
+
+#include <CoreFoundation/CoreFoundation.h>
+#include <Security/Security.h>
+#include <Security/SecIdentityPriv.h>
+#include <AssertMacros.h>
+
+#define CFReleaseSafe(CF) { CFTypeRef _cf = (CF); if (_cf) CFRelease(_cf); }
+
+const char *sslGetCipherSuiteString(SSLCipherSuite cs)
+{
+ static char noSuite[40];
+
+ switch (cs) {
+ /* TLS cipher suites, RFC 2246 */
+ case SSL_NULL_WITH_NULL_NULL: return "TLS_NULL_WITH_NULL_NULL";
+ case SSL_RSA_WITH_NULL_MD5: return "TLS_RSA_WITH_NULL_MD5";
+ case SSL_RSA_WITH_NULL_SHA: return "TLS_RSA_WITH_NULL_SHA";
+ case SSL_RSA_EXPORT_WITH_RC4_40_MD5: return "TLS_RSA_EXPORT_WITH_RC4_40_MD5";
+ case SSL_RSA_WITH_RC4_128_MD5: return "TLS_RSA_WITH_RC4_128_MD5";
+ case SSL_RSA_WITH_RC4_128_SHA: return "TLS_RSA_WITH_RC4_128_SHA";
+ case SSL_RSA_EXPORT_WITH_RC2_CBC_40_MD5: return "TLS_RSA_EXPORT_WITH_RC2_CBC_40_MD5";
+ case SSL_RSA_WITH_IDEA_CBC_SHA: return "TLS_RSA_WITH_IDEA_CBC_SHA";
+ case SSL_RSA_EXPORT_WITH_DES40_CBC_SHA: return "TLS_RSA_EXPORT_WITH_DES40_CBC_SHA";
+ case SSL_RSA_WITH_DES_CBC_SHA: return "TLS_RSA_WITH_DES_CBC_SHA";
+ case SSL_RSA_WITH_3DES_EDE_CBC_SHA: return "TLS_RSA_WITH_3DES_EDE_CBC_SHA";
+ case SSL_DH_DSS_EXPORT_WITH_DES40_CBC_SHA: return "TLS_DH_DSS_EXPORT_WITH_DES40_CBC_SHA";
+ case SSL_DH_DSS_WITH_DES_CBC_SHA: return "TLS_DH_DSS_WITH_DES_CBC_SHA";
+ case SSL_DH_DSS_WITH_3DES_EDE_CBC_SHA: return "TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA";
+ case SSL_DH_RSA_EXPORT_WITH_DES40_CBC_SHA: return "TLS_DH_RSA_EXPORT_WITH_DES40_CBC_SHA";
+ case SSL_DH_RSA_WITH_DES_CBC_SHA: return "TLS_DH_RSA_WITH_DES_CBC_SHA";
+ case SSL_DH_RSA_WITH_3DES_EDE_CBC_SHA: return "TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA";
+ case SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA: return "TLS_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA";
+ case SSL_DHE_DSS_WITH_DES_CBC_SHA: return "TLS_DHE_DSS_WITH_DES_CBC_SHA";
+ case SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA: return "TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA";
+ case SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA: return "TLS_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA";
+ case SSL_DHE_RSA_WITH_DES_CBC_SHA: return "TLS_DHE_RSA_WITH_DES_CBC_SHA";
+ case SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA: return "TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA";
+ case SSL_DH_anon_EXPORT_WITH_RC4_40_MD5: return "TLS_DH_anon_EXPORT_WITH_RC4_40_MD5";
+ case SSL_DH_anon_WITH_RC4_128_MD5: return "TLS_DH_anon_WITH_RC4_128_MD5";
+ case SSL_DH_anon_EXPORT_WITH_DES40_CBC_SHA: return "TLS_DH_anon_EXPORT_WITH_DES40_CBC_SHA";
+ case SSL_DH_anon_WITH_DES_CBC_SHA: return "TLS_DH_anon_WITH_DES_CBC_SHA";
+ case SSL_DH_anon_WITH_3DES_EDE_CBC_SHA: return "TLS_DH_anon_WITH_3DES_EDE_CBC_SHA";
+
+ /* SSLv3 Fortezza cipher suites, from NSS */
+ case SSL_FORTEZZA_DMS_WITH_NULL_SHA: return "SSL_FORTEZZA_DMS_WITH_NULL_SHA";
+ case SSL_FORTEZZA_DMS_WITH_FORTEZZA_CBC_SHA:return "SSL_FORTEZZA_DMS_WITH_FORTEZZA_CBC_SHA";
+
+ /* TLS addenda using AES-CBC, RFC 3268 */
+ case TLS_RSA_WITH_AES_128_CBC_SHA: return "TLS_RSA_WITH_AES_128_CBC_SHA";
+ case TLS_DH_DSS_WITH_AES_128_CBC_SHA: return "TLS_DH_DSS_WITH_AES_128_CBC_SHA";
+ case TLS_DH_RSA_WITH_AES_128_CBC_SHA: return "TLS_DH_RSA_WITH_AES_128_CBC_SHA";
+ case TLS_DHE_DSS_WITH_AES_128_CBC_SHA: return "TLS_DHE_DSS_WITH_AES_128_CBC_SHA";
+ case TLS_DHE_RSA_WITH_AES_128_CBC_SHA: return "TLS_DHE_RSA_WITH_AES_128_CBC_SHA";
+ case TLS_DH_anon_WITH_AES_128_CBC_SHA: return "TLS_DH_anon_WITH_AES_128_CBC_SHA";
+ case TLS_RSA_WITH_AES_256_CBC_SHA: return "TLS_RSA_WITH_AES_256_CBC_SHA";
+ case TLS_DH_DSS_WITH_AES_256_CBC_SHA: return "TLS_DH_DSS_WITH_AES_256_CBC_SHA";
+ case TLS_DH_RSA_WITH_AES_256_CBC_SHA: return "TLS_DH_RSA_WITH_AES_256_CBC_SHA";
+ case TLS_DHE_DSS_WITH_AES_256_CBC_SHA: return "TLS_DHE_DSS_WITH_AES_256_CBC_SHA";
+ case TLS_DHE_RSA_WITH_AES_256_CBC_SHA: return "TLS_DHE_RSA_WITH_AES_256_CBC_SHA";
+ case TLS_DH_anon_WITH_AES_256_CBC_SHA: return "TLS_DH_anon_WITH_AES_256_CBC_SHA";
+
+ /* ECDSA addenda, RFC 4492 */
+ case TLS_ECDH_ECDSA_WITH_NULL_SHA: return "TLS_ECDH_ECDSA_WITH_NULL_SHA";
+ case TLS_ECDH_ECDSA_WITH_RC4_128_SHA: return "TLS_ECDH_ECDSA_WITH_RC4_128_SHA";
+ case TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA: return "TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA";
+ case TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA: return "TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA";
+ case TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA: return "TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA";
+ case TLS_ECDHE_ECDSA_WITH_NULL_SHA: return "TLS_ECDHE_ECDSA_WITH_NULL_SHA";
+ case TLS_ECDHE_ECDSA_WITH_RC4_128_SHA: return "TLS_ECDHE_ECDSA_WITH_RC4_128_SHA";
+ case TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA: return "TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA";
+ case TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA: return "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA";
+ case TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA: return "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA";
+ case TLS_ECDH_RSA_WITH_NULL_SHA: return "TLS_ECDH_RSA_WITH_NULL_SHA";
+ case TLS_ECDH_RSA_WITH_RC4_128_SHA: return "TLS_ECDH_RSA_WITH_RC4_128_SHA";
+ case TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA: return "TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA";
+ case TLS_ECDH_RSA_WITH_AES_128_CBC_SHA: return "TLS_ECDH_RSA_WITH_AES_128_CBC_SHA";
+ case TLS_ECDH_RSA_WITH_AES_256_CBC_SHA: return "TLS_ECDH_RSA_WITH_AES_256_CBC_SHA";
+ case TLS_ECDHE_RSA_WITH_NULL_SHA: return "TLS_ECDHE_RSA_WITH_NULL_SHA";
+ case TLS_ECDHE_RSA_WITH_RC4_128_SHA: return "TLS_ECDHE_RSA_WITH_RC4_128_SHA";
+ case TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA: return "TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA";
+ case TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA: return "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA";
+ case TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA: return "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA";
+ case TLS_ECDH_anon_WITH_NULL_SHA: return "TLS_ECDH_anon_WITH_NULL_SHA";
+ case TLS_ECDH_anon_WITH_RC4_128_SHA: return "TLS_ECDH_anon_WITH_RC4_128_SHA";
+ case TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA: return "TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA";
+ case TLS_ECDH_anon_WITH_AES_128_CBC_SHA: return "TLS_ECDH_anon_WITH_AES_128_CBC_SHA";
+ case TLS_ECDH_anon_WITH_AES_256_CBC_SHA: return "TLS_ECDH_anon_WITH_AES_256_CBC_SHA";
+
+ /* TLS 1.2 addenda, RFC 5246 */
+ case TLS_RSA_WITH_AES_128_CBC_SHA256: return "TLS_RSA_WITH_AES_128_CBC_SHA256";
+ case TLS_RSA_WITH_AES_256_CBC_SHA256: return "TLS_RSA_WITH_AES_256_CBC_SHA256";
+ case TLS_DH_DSS_WITH_AES_128_CBC_SHA256: return "TLS_DH_DSS_WITH_AES_128_CBC_SHA256";
+ case TLS_DH_RSA_WITH_AES_128_CBC_SHA256: return "TLS_DH_RSA_WITH_AES_128_CBC_SHA256";
+ case TLS_DHE_DSS_WITH_AES_128_CBC_SHA256: return "TLS_DHE_DSS_WITH_AES_128_CBC_SHA256";
+ case TLS_DHE_RSA_WITH_AES_128_CBC_SHA256: return "TLS_DHE_RSA_WITH_AES_128_CBC_SHA256";
+ case TLS_DH_DSS_WITH_AES_256_CBC_SHA256: return "TLS_DH_DSS_WITH_AES_256_CBC_SHA256";
+ case TLS_DH_RSA_WITH_AES_256_CBC_SHA256: return "TLS_DH_RSA_WITH_AES_256_CBC_SHA256";
+ case TLS_DHE_DSS_WITH_AES_256_CBC_SHA256: return "TLS_DHE_DSS_WITH_AES_256_CBC_SHA256";
+ case TLS_DHE_RSA_WITH_AES_256_CBC_SHA256: return "TLS_DHE_RSA_WITH_AES_256_CBC_SHA256";
+ case TLS_DH_anon_WITH_AES_128_CBC_SHA256: return "TLS_DH_anon_WITH_AES_128_CBC_SHA256";
+ case TLS_DH_anon_WITH_AES_256_CBC_SHA256: return "TLS_DH_anon_WITH_AES_256_CBC_SHA256";
+
+ /* TLS addenda using AES-GCM, RFC 5288 */
+ case TLS_RSA_WITH_AES_128_GCM_SHA256: return "TLS_RSA_WITH_AES_128_GCM_SHA256";
+ case TLS_RSA_WITH_AES_256_GCM_SHA384: return "TLS_DHE_RSA_WITH_AES_128_GCM_SHA256";
+ case TLS_DHE_RSA_WITH_AES_128_GCM_SHA256: return "TLS_DHE_RSA_WITH_AES_128_GCM_SHA256";
+ case TLS_DHE_RSA_WITH_AES_256_GCM_SHA384: return "TLS_DHE_RSA_WITH_AES_256_GCM_SHA384";
+ case TLS_DH_RSA_WITH_AES_128_GCM_SHA256: return "TLS_DH_RSA_WITH_AES_128_GCM_SHA256";
+ case TLS_DH_RSA_WITH_AES_256_GCM_SHA384: return "TLS_DH_RSA_WITH_AES_256_GCM_SHA384";
+ case TLS_DHE_DSS_WITH_AES_128_GCM_SHA256: return "TLS_DHE_DSS_WITH_AES_128_GCM_SHA256";
+ case TLS_DHE_DSS_WITH_AES_256_GCM_SHA384: return "TLS_DHE_DSS_WITH_AES_256_GCM_SHA384";
+ case TLS_DH_DSS_WITH_AES_128_GCM_SHA256: return "TLS_DH_DSS_WITH_AES_128_GCM_SHA256";
+ case TLS_DH_DSS_WITH_AES_256_GCM_SHA384: return "TLS_DH_DSS_WITH_AES_256_GCM_SHA384";
+ case TLS_DH_anon_WITH_AES_128_GCM_SHA256: return "TLS_DH_anon_WITH_AES_128_GCM_SHA256";
+ case TLS_DH_anon_WITH_AES_256_GCM_SHA384: return "TLS_DH_anon_WITH_AES_256_GCM_SHA384";
+
+ /* ECDSA addenda, RFC 5289 */
+ case TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256: return "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256";
+ case TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384: return "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384";
+ case TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256: return "TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256";
+ case TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384: return "TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384";
+ case TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256: return "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256";
+ case TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384: return "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384";
+ case TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256: return "TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256";
+ case TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384: return "TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384";
+ case TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256: return "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256";
+ case TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384: return "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384";
+ case TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256: return "TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256";
+ case TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384: return "TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384";
+ case TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256: return "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256";
+ case TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384: return "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384";
+ case TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256: return "TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256";
+ case TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384: return "TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384";
+
+ /*
+ * Tags for SSL 2 cipher kinds which are not specified for SSL 3.
+ */
+ case SSL_RSA_WITH_RC2_CBC_MD5: return "TLS_RSA_WITH_RC2_CBC_MD5";
+ case SSL_RSA_WITH_IDEA_CBC_MD5: return "TLS_RSA_WITH_IDEA_CBC_MD5";
+ case SSL_RSA_WITH_DES_CBC_MD5: return "TLS_RSA_WITH_DES_CBC_MD5";
+ case SSL_RSA_WITH_3DES_EDE_CBC_MD5: return "TLS_RSA_WITH_3DES_EDE_CBC_MD5";
+ case SSL_NO_SUCH_CIPHERSUITE: return "SSL_NO_SUCH_CIPHERSUITE";
+
+ default:
+ snprintf(noSuite, sizeof(noSuite), "Unknown ciphersuite 0x%04x", (unsigned)cs);
+ return noSuite;
+ }
+}
+
+/*
+ * Given a SSLProtocolVersion - typically from SSLGetProtocolVersion -
+ * return a string representation.
+ */
+const char *sslGetProtocolVersionString(SSLProtocol prot)
+{
+ static char noProt[20];
+
+ switch(prot) {
+ case kSSLProtocolUnknown: return "kSSLProtocolUnknown";
+ case kSSLProtocol2: return "kSSLProtocol2";
+ case kSSLProtocol3: return "kSSLProtocol3";
+ case kSSLProtocol3Only: return "kSSLProtocol3Only";
+ case kTLSProtocol1: return "kTLSProtocol1";
+ case kTLSProtocol1Only: return "kTLSProtocol1Only";
+ case kTLSProtocol11: return "kTLSProtocol11";
+ case kTLSProtocol12: return "kTLSProtocol12";
+ default:
+ sprintf(noProt, "Unknown (%d)", (unsigned)prot);
+ return noProt;
+ }
+}
+
+/*
+ * Return string representation of SecureTransport-related OSStatus.
+ */
+const char *sslGetSSLErrString(OSStatus err)
+{
+ static char errSecSuccessStr[20];
+
+ switch(err) {
+ case errSecSuccess: return "errSecSuccess";
+ case errSecAllocate: return "errSecAllocate";
+ case errSecParam: return "errSecParam";
+ case errSecUnimplemented: return "errSecUnimplemented";
+ case errSecIO: return "errSecIO";
+ case errSecBadReq: return "errSecBadReq";
+ /* SSL errors */
+ case errSSLProtocol: return "errSSLProtocol";
+ case errSSLNegotiation: return "errSSLNegotiation";
+ case errSSLFatalAlert: return "errSSLFatalAlert";
+ case errSSLWouldBlock: return "errSSLWouldBlock";
+ case errSSLSessionNotFound: return "errSSLSessionNotFound";
+ case errSSLClosedGraceful: return "errSSLClosedGraceful";
+ case errSSLClosedAbort: return "errSSLClosedAbort";
+ case errSSLXCertChainInvalid: return "errSSLXCertChainInvalid";
+ case errSSLBadCert: return "errSSLBadCert";
+ case errSSLCrypto: return "errSSLCrypto";
+ case errSSLInternal: return "errSSLInternal";
+ case errSSLModuleAttach: return "errSSLModuleAttach";
+ case errSSLUnknownRootCert: return "errSSLUnknownRootCert";
+ case errSSLNoRootCert: return "errSSLNoRootCert";
+ case errSSLCertExpired: return "errSSLCertExpired";
+ case errSSLCertNotYetValid: return "errSSLCertNotYetValid";
+ case errSSLClosedNoNotify: return "errSSLClosedNoNotify";
+ case errSSLBufferOverflow: return "errSSLBufferOverflow";
+ case errSSLBadCipherSuite: return "errSSLBadCipherSuite";
+ /* TLS/Panther addenda */
+ case errSSLPeerUnexpectedMsg: return "errSSLPeerUnexpectedMsg";
+ case errSSLPeerBadRecordMac: return "errSSLPeerBadRecordMac";
+ case errSSLPeerDecryptionFail: return "errSSLPeerDecryptionFail";
+ case errSSLPeerRecordOverflow: return "errSSLPeerRecordOverflow";
+ case errSSLPeerDecompressFail: return "errSSLPeerDecompressFail";
+ case errSSLPeerHandshakeFail: return "errSSLPeerHandshakeFail";
+ case errSSLPeerBadCert: return "errSSLPeerBadCert";
+ case errSSLPeerUnsupportedCert: return "errSSLPeerUnsupportedCert";
+ case errSSLPeerCertRevoked: return "errSSLPeerCertRevoked";
+ case errSSLPeerCertExpired: return "errSSLPeerCertExpired";
+ case errSSLPeerCertUnknown: return "errSSLPeerCertUnknown";
+ case errSSLIllegalParam: return "errSSLIllegalParam";
+ case errSSLPeerUnknownCA: return "errSSLPeerUnknownCA";
+ case errSSLPeerAccessDenied: return "errSSLPeerAccessDenied";
+ case errSSLPeerDecodeError: return "errSSLPeerDecodeError";
+ case errSSLPeerDecryptError: return "errSSLPeerDecryptError";
+ case errSSLPeerExportRestriction: return "errSSLPeerExportRestriction";
+ case errSSLPeerProtocolVersion: return "errSSLPeerProtocolVersion";
+ case errSSLPeerInsufficientSecurity:return "errSSLPeerInsufficientSecurity";
+ case errSSLPeerInternalError: return "errSSLPeerInternalError";
+ case errSSLPeerUserCancelled: return "errSSLPeerUserCancelled";
+ case errSSLPeerNoRenegotiation: return "errSSLPeerNoRenegotiation";
+ case errSSLHostNameMismatch: return "errSSLHostNameMismatch";
+ case errSSLConnectionRefused: return "errSSLConnectionRefused";
+ case errSSLDecryptionFail: return "errSSLDecryptionFail";
+ case errSSLBadRecordMac: return "errSSLBadRecordMac";
+ case errSSLRecordOverflow: return "errSSLRecordOverflow";
+ case errSSLBadConfiguration: return "errSSLBadConfiguration";
+
+ /* some from the Sec layer */
+ case errSecNotAvailable: return "errSecNotAvailable";
+ case errSecDuplicateItem: return "errSecDuplicateItem";
+ case errSecItemNotFound: return "errSecItemNotFound";
+#if !TARGET_OS_IPHONE
+ case errSecReadOnly: return "errSecReadOnly";
+ case errSecAuthFailed: return "errSecAuthFailed";
+ case errSecNoSuchKeychain: return "errSecNoSuchKeychain";
+ case errSecInvalidKeychain: return "errSecInvalidKeychain";
+ case errSecNoSuchAttr: return "errSecNoSuchAttr";
+ case errSecInvalidItemRef: return "errSecInvalidItemRef";
+ case errSecInvalidSearchRef: return "errSecInvalidSearchRef";
+ case errSecNoSuchClass: return "errSecNoSuchClass";
+ case errSecNoDefaultKeychain: return "errSecNoDefaultKeychain";
+ case errSecWrongSecVersion: return "errSecWrongSecVersion";
+ case errSecInvalidTrustSettings: return "errSecInvalidTrustSettings";
+ case errSecNoTrustSettings: return "errSecNoTrustSettings";
+#endif
+ default:
+#if 0
+ if (err < (CSSM_BASE_ERROR +
+ (CSSM_ERRORCODE_MODULE_EXTENT * 8)))
+ {
+ /* assume CSSM error */
+ return cssmErrToStr(err);
+ }
+ else
+#endif
+ {
+ sprintf(errSecSuccessStr, "Unknown (%d)", (unsigned)err);
+ return errSecSuccessStr;
+ }
+ }
+}
+
+void printSslErrStr(
+ const char *op,
+ OSStatus err)
+{
+ printf("*** %s: %s\n", op, sslGetSSLErrString(err));
+}
+
+const char *sslGetClientCertStateString(SSLClientCertificateState state)
+{
+ static char noState[20];
+
+ switch(state) {
+ case kSSLClientCertNone: return "ClientCertNone";
+ case kSSLClientCertRequested: return "CertRequested";
+ case kSSLClientCertSent: return "ClientCertSent";
+ case kSSLClientCertRejected: return "ClientCertRejected";
+ default:
+ sprintf(noState, "Unknown (%d)", (unsigned)state);
+ return noState;
+ }
+
+}
+
+const char *sslGetClientAuthTypeString(SSLClientAuthenticationType authType)
+{
+ static char noType[20];
+
+ switch(authType) {
+ case SSLClientAuthNone: return "None";
+ case SSLClientAuth_RSASign: return "RSASign";
+ case SSLClientAuth_DSSSign: return "DSSSign";
+ case SSLClientAuth_RSAFixedDH: return "RSAFixedDH";
+ case SSLClientAuth_DSS_FixedDH: return "DSS_FixedDH";
+ case SSLClientAuth_ECDSASign: return "ECDSASign";
+ case SSLClientAuth_RSAFixedECDH: return "RSAFixedECDH";
+ case SSLClientAuth_ECDSAFixedECDH: return "ECDSAFixedECDH";
+ default:
+ sprintf(noType, "Unknown (%d)", (unsigned)authType);
+ return noType;
+ }
+}
+
+/*
+ * Convert a keychain name (which may be NULL) into the CFArrayRef required
+ * by SSLSetCertificate. This is a bare-bones example of this operation,
+ * since it requires and assumes that there is exactly one SecIdentity
+ * in the keychain - i.e., there is exactly one matching cert/private key
+ * pair. A real world server would probably search a keychain for a SecIdentity
+ * matching some specific criteria.
+ */
+CFArrayRef getSslCerts(
+ const char *kcName, // may be NULL, i.e., use default
+ bool encryptOnly,
+ bool completeCertChain,
+ const char *anchorFile, // optional trusted anchor
+ SecKeychainRef *pKcRef) // RETURNED
+{
+#if 0
+ SecKeychainRef kcRef = nil;
+ OSStatus ortn;
+
+ *pKcRef = nil;
+
+ /* pick a keychain */
+ if(kcName) {
+ ortn = SecKeychainOpen(kcName, &kcRef);
+ if(ortn) {
+ printf("SecKeychainOpen returned %d.\n", (int)ortn);
+ printf("Cannot open keychain at %s. Aborting.\n", kcName);
+ return NULL;
+ }
+ }
+ else {
+ /* use default keychain */
+ ortn = SecKeychainCopyDefault(&kcRef);
+ if(ortn) {
+ printf("SecKeychainCopyDefault returned %d; aborting.\n", (int)ortn);
+ return nil;
+ }
+ }
+ *pKcRef = kcRef;
+ return sslKcRefToCertArray(kcRef, encryptOnly, completeCertChain, anchorFile);
+#elif TARGET_OS_IOS
+ SecCertificateRef cert = NULL;
+ SecIdentityRef identity = NULL;
+ CFMutableArrayRef certificates = NULL, result = NULL;
+ CFMutableDictionaryRef certQuery = NULL, keyQuery = NULL, keyResult = NULL;
+ SecTrustRef trust = NULL;
+ SecKeyRef key = NULL;
+ CFTypeRef pkdigest = NULL;
+
+ // Find the first private key in the keychain and return both its
+ // attributes and a ref to it.
+ require(keyQuery = CFDictionaryCreateMutable(NULL, 0, NULL, NULL), errOut);
+ CFDictionaryAddValue(keyQuery, kSecClass, kSecClassKey);
+ CFDictionaryAddValue(keyQuery, kSecAttrKeyClass, kSecAttrKeyClassPrivate);
+ CFDictionaryAddValue(keyQuery, kSecReturnRef, kCFBooleanTrue);
+ CFDictionaryAddValue(keyQuery, kSecReturnAttributes, kCFBooleanTrue);
+ require_noerr(SecItemCopyMatching(keyQuery, (CFTypeRef *)&keyResult),
+ errOut);
+ require(key = (SecKeyRef)CFDictionaryGetValue(keyResult, kSecValueRef),
+ errOut);
+ require(pkdigest = CFDictionaryGetValue(keyResult, kSecAttrApplicationLabel),
+ errOut);
+
+ // Find the first certificate that has the same public key hash as the
+ // returned private key and return it as a ref.
+ require(certQuery = CFDictionaryCreateMutable(NULL, 0, NULL, NULL), errOut);
+ CFDictionaryAddValue(certQuery, kSecClass, kSecClassCertificate);
+ CFDictionaryAddValue(certQuery, kSecAttrPublicKeyHash, pkdigest);
+ CFDictionaryAddValue(certQuery, kSecReturnRef, kCFBooleanTrue);
+ require_noerr(SecItemCopyMatching(certQuery, (CFTypeRef *)&cert), errOut);
+
+ // Create an identity from the key and certificate.
+ require(identity = SecIdentityCreate(NULL, cert, key), errOut);
+
+ // Build a (partial) certificate chain from cert
+ require(certificates = CFArrayCreateMutable(NULL, 0,
+ &kCFTypeArrayCallBacks), errOut);
+ CFArrayAppendValue(certificates, cert);
+ require_noerr(SecTrustCreateWithCertificates(certificates, NULL, &trust),
+ errOut);
+ SecTrustResultType tresult;
+ require_noerr(SecTrustEvaluate(trust, &tresult), errOut);
+
+ CFIndex certCount, ix;
+ // We need at least 1 certificate
+ require(certCount = SecTrustGetCertificateCount(trust), errOut);
+
+ // Build a result where element 0 is the identity and the other elements
+ // are the certs in the chain starting at the first intermediate up to the
+ // anchor, if we found one, or as far as we were able to build the chain
+ // if not.
+ require(result = CFArrayCreateMutable(NULL, certCount, &kCFTypeArrayCallBacks),
+ errOut);
+
+ // We are commited to returning a result now, so do not use require below
+ // this line without setting result to NULL again.
+ CFArrayAppendValue(result, identity);
+ for (ix = 1; ix < certCount; ++ix) {
+ CFArrayAppendValue(result, SecTrustGetCertificateAtIndex(trust, ix));
+ }
+
+errOut:
+ CFReleaseSafe(trust);
+ CFReleaseSafe(certificates);
+ CFReleaseSafe(identity);
+ CFReleaseSafe(cert);
+ CFReleaseSafe(certQuery);
+ CFReleaseSafe(keyResult);
+ CFReleaseSafe(keyQuery);
+
+ return result;
+
+#else /* !TARGET_OS_IOS */
+ SecIdentityRef identity = NULL;
+ CFMutableDictionaryRef query = NULL;
+ CFArrayRef items = NULL;
+ require(query = CFDictionaryCreateMutable(NULL, 0, NULL, NULL), errOut);
+ CFDictionaryAddValue(query, kSecClass, kSecClassIdentity);
+ CFDictionaryAddValue(query, kSecReturnRef, kCFBooleanTrue);
+ require_noerr(SecItemCopyMatching(query, (CFTypeRef *)&identity), errOut);
+
+ items = CFArrayCreate(kCFAllocatorDefault,
+ (const void **)&identity, 1, &kCFTypeArrayCallBacks);
+
+errOut:
+ CFReleaseSafe(identity);
+ CFReleaseSafe(query);
+
+ return items;
+
+#endif
+
+}
+
+#if 0
+/*
+ * Determine if specified SecCertificateRef is a self-signed cert.
+ * We do this by comparing the subject and issuerr names; no cryptographic
+ * verification is performed.
+ *
+ * Returns true if the cert appears to be a root.
+ */
+static bool isCertRefRoot(
+ SecCertificateRef certRef)
+{
+ bool brtn = false;
+#if 0
+ /* just search for the two attrs we want */
+ UInt32 tags[2] = {kSecSubjectItemAttr, kSecIssuerItemAttr};
+ SecKeychainAttributeInfo attrInfo;
+ attrInfo.count = 2;
+ attrInfo.tag = tags;
+ attrInfo.format = NULL;
+ SecKeychainAttributeList *attrList = NULL;
+ SecKeychainAttribute *attr1 = NULL;
+ SecKeychainAttribute *attr2 = NULL;
+
+ OSStatus ortn = SecKeychainItemCopyAttributesAndData(
+ (SecKeychainItemRef)certRef,
+ &attrInfo,
+ NULL, // itemClass
+ &attrList,
+ NULL, // length - don't need the data
+ NULL); // outData
+ if(ortn) {
+ cssmPerror("SecKeychainItemCopyAttributesAndData", ortn);
+ /* may want to be a bit more robust here, but this should
+ * never happen */
+ return false;
+ }
+ /* subsequent errors to errOut: */
+
+ if((attrList == NULL) || (attrList->count != 2)) {
+ printf("***Unexpected result fetching label attr\n");
+ goto errOut;
+ }
+
+ /* rootness is just byte-for-byte compare of the two names */
+ attr1 = &attrList->attr[0];
+ attr2 = &attrList->attr[1];
+ if(attr1->length == attr2->length) {
+ if(memcmp(attr1->data, attr2->data, attr1->length) == 0) {
+ brtn = true;
+ }
+ }
+errOut:
+ SecKeychainItemFreeAttributesAndData(attrList, NULL);
+#endif
+ return brtn;
+}
+#endif
+
+#if 0
+/*
+ * Given a SecIdentityRef, do our best to construct a complete, ordered, and
+ * verified cert chain, returning the result in a CFArrayRef. The result is
+ * suitable for use when calling SSLSetCertificate().
+ */
+OSStatus sslCompleteCertChain(
+ SecIdentityRef identity,
+ SecCertificateRef trustedAnchor, // optional additional trusted anchor
+ bool includeRoot, // include the root in outArray
+ CFArrayRef *outArray) // created and RETURNED
+{
+ CFMutableArrayRef certArray;
+ SecTrustRef secTrust = NULL;
+ SecPolicyRef policy = NULL;
+ SecPolicySearchRef policySearch = NULL;
+ SecTrustResultType secTrustResult;
+ CSSM_TP_APPLE_EVIDENCE_INFO *dummyEv; // not used
+ CFArrayRef certChain = NULL; // constructed chain
+ CFIndex numResCerts;
+
+ certArray = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
+ CFArrayAppendValue(certArray, identity);
+
+ /*
+ * Case 1: identity is a root; we're done. Note that this case
+ * overrides the includeRoot argument.
+ */
+ SecCertificateRef certRef;
+ OSStatus ortn = SecIdentityCopyCertificate(identity, &certRef);
+ if(ortn) {
+ /* should never happen */
+ cssmPerror("SecIdentityCopyCertificate", ortn);
+ return ortn;
+ }
+ bool isRoot = isCertRefRoot(certRef);
+ if(isRoot) {
+ *outArray = certArray;
+ CFRelease(certRef);
+ return errSecSuccess;
+ }
+
+ /*
+ * Now use SecTrust to get a complete cert chain, using all of the
+ * user's keychains to look for intermediate certs.
+ * NOTE this does NOT handle root certs which are not in the system
+ * root cert DB. (The above case, where the identity is a root cert, does.)
+ */
+ CFMutableArrayRef subjCerts = CFArrayCreateMutable(NULL, 1, &kCFTypeArrayCallBacks);
+ CFArraySetValueAtIndex(subjCerts, 0, certRef);
+
+ /* the array owns the subject cert ref now */
+ CFRelease(certRef);
+
+ /* Get a SecPolicyRef for generic X509 cert chain verification */
+ ortn = SecPolicySearchCreate(CSSM_CERT_X_509v3,
+ &CSSMOID_APPLE_X509_BASIC,
+ NULL, // value
+ &policySearch);
+ if(ortn) {
+ cssmPerror("SecPolicySearchCreate", ortn);
+ goto errOut;
+ }
+ ortn = SecPolicySearchCopyNext(policySearch, &policy);
+ if(ortn) {
+ cssmPerror("SecPolicySearchCopyNext", ortn);
+ goto errOut;
+ }
+
+ /* build a SecTrustRef for specified policy and certs */
+ ortn = SecTrustCreateWithCertificates(subjCerts,
+ policy, &secTrust);
+ if(ortn) {
+ cssmPerror("SecTrustCreateWithCertificates", ortn);
+ goto errOut;
+ }
+
+ if(trustedAnchor) {
+ /*
+ * Tell SecTrust to trust this one in addition to the current
+ * trusted system-wide anchors.
+ */
+ CFMutableArrayRef newAnchors;
+ CFArrayRef currAnchors;
+
+ ortn = SecTrustCopyAnchorCertificates(&currAnchors);
+ if(ortn) {
+ /* should never happen */
+ cssmPerror("SecTrustCopyAnchorCertificates", ortn);
+ goto errOut;
+ }
+ newAnchors = CFArrayCreateMutableCopy(NULL,
+ CFArrayGetCount(currAnchors) + 1,
+ currAnchors);
+ CFRelease(currAnchors);
+ CFArrayAppendValue(newAnchors, trustedAnchor);
+ ortn = SecTrustSetAnchorCertificates(secTrust, newAnchors);
+ CFRelease(newAnchors);
+ if(ortn) {
+ cssmPerror("SecTrustSetAnchorCertificates", ortn);
+ goto errOut;
+ }
+ }
+ /* evaluate: GO */
+ ortn = SecTrustEvaluate(secTrust, &secTrustResult);
+ if(ortn) {
+ cssmPerror("SecTrustEvaluate", ortn);
+ goto errOut;
+ }
+ switch(secTrustResult) {
+ case kSecTrustResultUnspecified:
+ /* cert chain valid, no special UserTrust assignments */
+ case kSecTrustResultProceed:
+ /* cert chain valid AND user explicitly trusts this */
+ break;
+ default:
+ /*
+ * Cert chain construction failed.
+ * Just go with the single subject cert we were given.
+ */
+ printf("***Warning: could not construct completed cert chain\n");
+ ortn = errSecSuccess;
+ goto errOut;
+ }
+
+ /* get resulting constructed cert chain */
+ ortn = SecTrustGetResult(secTrust, &secTrustResult, &certChain, &dummyEv);
+ if(ortn) {
+ cssmPerror("SecTrustEvaluate", ortn);
+ goto errOut;
+ }
+
+ /*
+ * Copy certs from constructed chain to our result array, skipping
+ * the leaf (which is already there, as a SecIdentityRef) and possibly
+ * a root.
+ */
+ numResCerts = CFArrayGetCount(certChain);
+ if(numResCerts < 2) {
+ /*
+ * Can't happen: if subject was a root, we'd already have returned.
+ * If chain doesn't verify to a root, we'd have bailed after
+ * SecTrustEvaluate().
+ */
+ printf("***sslCompleteCertChain screwup: numResCerts %d\n",
+ (int)numResCerts);
+ ortn = errSecSuccess;
+ goto errOut;
+ }
+ if(!includeRoot) {
+ /* skip the last (root) cert) */
+ numResCerts--;
+ }
+ for(CFIndex dex=1; dex<numResCerts; dex++) {
+ certRef = (SecCertificateRef)CFArrayGetValueAtIndex(certChain, dex);
+ CFArrayAppendValue(certArray, certRef);
+ }
+errOut:
+ /* clean up */
+ if(secTrust) {
+ CFRelease(secTrust);
+ }
+ if(subjCerts) {
+ CFRelease(subjCerts);
+ }
+ if(policy) {
+ CFRelease(policy);
+ }
+ if(policySearch) {
+ CFRelease(policySearch);
+ }
+ *outArray = certArray;
+ return ortn;
+}
+
+
+/*
+ * Given an open keychain, find a SecIdentityRef and munge it into
+ * a CFArrayRef required by SSLSetCertificate().
+ */
+CFArrayRef sslKcRefToCertArray(
+ SecKeychainRef kcRef,
+ bool encryptOnly,
+ bool completeCertChain,
+ const char *trustedAnchorFile)
+{
+ /* quick check to make sure the keychain exists */
+ SecKeychainStatus kcStat;
+ OSStatus ortn = SecKeychainGetStatus(kcRef, &kcStat);
+ if(ortn) {
+ printSslErrStr("SecKeychainGetStatus", ortn);
+ printf("Can not open keychain. Aborting.\n");
+ return nil;
+ }
+
+ /*
+ * Search for "any" identity matching specified key use;
+ * in this app, we expect there to be exactly one.
+ */
+ SecIdentitySearchRef srchRef = nil;
+ ortn = SecIdentitySearchCreate(kcRef,
+ encryptOnly ? CSSM_KEYUSE_DECRYPT : CSSM_KEYUSE_SIGN,
+ &srchRef);
+ if(ortn) {
+ printf("SecIdentitySearchCreate returned %d.\n", (int)ortn);
+ printf("Cannot find signing key in keychain. Aborting.\n");
+ return nil;
+ }
+ SecIdentityRef identity = nil;
+ ortn = SecIdentitySearchCopyNext(srchRef, &identity);
+ if(ortn) {
+ printf("SecIdentitySearchCopyNext returned %d.\n", (int)ortn);
+ printf("Cannot find signing key in keychain. Aborting.\n");
+ return nil;
+ }
+ if(CFGetTypeID(identity) != SecIdentityGetTypeID()) {
+ printf("SecIdentitySearchCopyNext CFTypeID failure!\n");
+ return nil;
+ }
+
+ /*
+ * Found one.
+ */
+ if(completeCertChain) {
+ /*
+ * Place it and the other certs needed to verify it -
+ * up to but not including the root - in a CFArray.
+ */
+ SecCertificateRef anchorCert = NULL;
+ if(trustedAnchorFile) {
+ ortn = sslReadAnchor(trustedAnchorFile, &anchorCert);
+ if(ortn) {
+ printf("***Error reading anchor file\n");
+ }
+ }
+ CFArrayRef ca;
+ ortn = sslCompleteCertChain(identity, anchorCert, false, &ca);
+ if(anchorCert) {
+ CFRelease(anchorCert);
+ }
+ return ca;
+ }
+ else {
+ /* simple case, just this one identity */
+ CFArrayRef ca = CFArrayCreate(NULL,
+ (const void **)&identity,
+ 1,
+ NULL);
+ if(ca == nil) {
+ printf("CFArrayCreate error\n");
+ }
+ return ca;
+ }
+}
+#endif
+
+OSStatus addTrustedSecCert(
+ SSLContextRef ctx,
+ SecCertificateRef secCert,
+ bool replaceAnchors)
+{
+ OSStatus ortn;
+ CFMutableArrayRef array;
+
+ if(secCert == NULL) {
+ printf("***addTrustedSecCert screwup\n");
+ return errSecParam;
+ }
+ array = CFArrayCreateMutable(kCFAllocatorDefault,
+ (CFIndex)1, &kCFTypeArrayCallBacks);
+ if(array == NULL) {
+ return errSecAllocate;
+ }
+ CFArrayAppendValue(array, secCert);
+ ortn = SSLSetTrustedRoots(ctx, array, replaceAnchors ? true : false);
+ if(ortn) {
+ printSslErrStr("SSLSetTrustedRoots", ortn);
+ }
+ CFRelease(array);
+ return ortn;
+}
+
+OSStatus sslReadAnchor(
+ const char *anchorFile,
+ SecCertificateRef *certRef)
+{
+ SecCertificateRef secCert;
+ unsigned char *certData;
+ unsigned certLen;
+ CFDataRef dataRef;
+
+ if(readFile(anchorFile, &certData, &certLen)) {
+ return -1;
+ }
+ dataRef = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault,
+ (const UInt8 *)certData, (CFIndex)certLen, kCFAllocatorNull);
+ secCert = SecCertificateCreateWithData(kCFAllocatorDefault, dataRef);
+ CFReleaseSafe(dataRef);
+ free(certData);
+ if(!secCert) {
+ printf("***SecCertificateCreateWithData returned NULL\n");
+ return errSecParam;
+ }
+ if (certRef) {
+ *certRef = secCert;
+ }
+ return errSecSuccess;
+}
+
+OSStatus sslAddTrustedRoot(
+ SSLContextRef ctx,
+ const char *anchorFile,
+ bool replaceAnchors)
+{
+ return 0;
+}
+
+OSStatus addIdentityAsTrustedRoot(
+ SSLContextRef ctx,
+ CFArrayRef identArray)
+{
+ return errSecSuccess;
+}
+
+/*
+ * Lists of SSLCipherSuites used in sslSetCipherRestrictions. Note that the
+ * SecureTransport library does not implement all of these; we only specify
+ * the ones it claims to support.
+ */
+const SSLCipherSuite suites40[] = {
+ SSL_RSA_EXPORT_WITH_RC4_40_MD5,
+ SSL_RSA_EXPORT_WITH_RC2_CBC_40_MD5,
+ SSL_RSA_EXPORT_WITH_DES40_CBC_SHA,
+ SSL_DH_DSS_EXPORT_WITH_DES40_CBC_SHA,
+ SSL_DH_RSA_EXPORT_WITH_DES40_CBC_SHA,
+ SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA,
+ SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA,
+ SSL_DH_anon_EXPORT_WITH_RC4_40_MD5,
+ SSL_DH_anon_EXPORT_WITH_DES40_CBC_SHA,
+ SSL_NO_SUCH_CIPHERSUITE
+};
+const SSLCipherSuite suitesDES[] = {
+ SSL_RSA_WITH_DES_CBC_SHA,
+ SSL_DH_DSS_WITH_DES_CBC_SHA,
+ SSL_DH_RSA_WITH_DES_CBC_SHA,
+ SSL_DHE_DSS_WITH_DES_CBC_SHA,
+ SSL_DHE_RSA_WITH_DES_CBC_SHA,
+ SSL_DH_anon_WITH_DES_CBC_SHA,
+ SSL_RSA_WITH_DES_CBC_MD5,
+ SSL_NO_SUCH_CIPHERSUITE
+};
+const SSLCipherSuite suitesDES40[] = {
+ SSL_RSA_EXPORT_WITH_DES40_CBC_SHA,
+ SSL_DH_DSS_EXPORT_WITH_DES40_CBC_SHA,
+ SSL_DH_RSA_EXPORT_WITH_DES40_CBC_SHA,
+ SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA,
+ SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA,
+ SSL_DH_anon_EXPORT_WITH_DES40_CBC_SHA,
+ SSL_NO_SUCH_CIPHERSUITE
+};
+const SSLCipherSuite suites3DES[] = {
+ SSL_RSA_WITH_3DES_EDE_CBC_SHA,
+ SSL_DH_DSS_WITH_3DES_EDE_CBC_SHA,
+ SSL_DH_RSA_WITH_3DES_EDE_CBC_SHA,
+ SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA,
+ SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA,
+ SSL_DH_anon_WITH_3DES_EDE_CBC_SHA,
+ SSL_RSA_WITH_3DES_EDE_CBC_MD5,
+ SSL_NO_SUCH_CIPHERSUITE
+};
+const SSLCipherSuite suitesRC4[] = {
+ SSL_RSA_WITH_RC4_128_MD5,
+ SSL_RSA_WITH_RC4_128_SHA,
+ SSL_DH_anon_WITH_RC4_128_MD5,
+ SSL_NO_SUCH_CIPHERSUITE
+};
+const SSLCipherSuite suitesRC4_40[] = {
+ SSL_RSA_EXPORT_WITH_RC4_40_MD5,
+ SSL_DH_anon_EXPORT_WITH_RC4_40_MD5,
+ SSL_NO_SUCH_CIPHERSUITE
+};
+const SSLCipherSuite suitesRC2[] = {
+ SSL_RSA_WITH_RC2_CBC_MD5,
+ SSL_RSA_EXPORT_WITH_RC2_CBC_40_MD5,
+ SSL_NO_SUCH_CIPHERSUITE
+};
+const SSLCipherSuite suitesAES128[] = {
+ TLS_RSA_WITH_AES_128_CBC_SHA,
+ TLS_DH_DSS_WITH_AES_128_CBC_SHA,
+ TLS_DH_RSA_WITH_AES_128_CBC_SHA,
+ TLS_DHE_DSS_WITH_AES_128_CBC_SHA,
+ TLS_DHE_RSA_WITH_AES_128_CBC_SHA,
+ TLS_DH_anon_WITH_AES_128_CBC_SHA,
+ SSL_NO_SUCH_CIPHERSUITE
+};
+const SSLCipherSuite suitesAES256[] = {
+ TLS_RSA_WITH_AES_256_CBC_SHA,
+ TLS_DH_DSS_WITH_AES_256_CBC_SHA,
+ TLS_DH_RSA_WITH_AES_256_CBC_SHA,
+ TLS_DHE_DSS_WITH_AES_256_CBC_SHA,
+ TLS_DHE_RSA_WITH_AES_256_CBC_SHA,
+ TLS_DH_anon_WITH_AES_256_CBC_SHA,
+ SSL_NO_SUCH_CIPHERSUITE
+};
+const SSLCipherSuite suitesDH[] = {
+ SSL_DH_DSS_WITH_DES_CBC_SHA,
+ SSL_DH_DSS_WITH_3DES_EDE_CBC_SHA,
+ SSL_DH_DSS_EXPORT_WITH_DES40_CBC_SHA,
+ SSL_DH_RSA_WITH_DES_CBC_SHA,
+ SSL_DH_RSA_WITH_3DES_EDE_CBC_SHA,
+ SSL_DH_RSA_EXPORT_WITH_DES40_CBC_SHA,
+ SSL_DHE_DSS_WITH_DES_CBC_SHA,
+ SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA,
+ SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA,
+ SSL_DHE_RSA_WITH_DES_CBC_SHA,
+ SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA,
+ SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA,
+ SSL_DH_anon_WITH_RC4_128_MD5,
+ SSL_DH_anon_WITH_DES_CBC_SHA,
+ SSL_DH_anon_WITH_3DES_EDE_CBC_SHA,
+ SSL_DH_anon_EXPORT_WITH_RC4_40_MD5,
+ SSL_DH_anon_EXPORT_WITH_DES40_CBC_SHA,
+ TLS_DH_DSS_WITH_AES_128_CBC_SHA,
+ TLS_DH_RSA_WITH_AES_128_CBC_SHA,
+ TLS_DHE_DSS_WITH_AES_128_CBC_SHA,
+ TLS_DHE_RSA_WITH_AES_128_CBC_SHA,
+ TLS_DH_anon_WITH_AES_128_CBC_SHA,
+ TLS_DH_DSS_WITH_AES_256_CBC_SHA,
+ TLS_DH_RSA_WITH_AES_256_CBC_SHA,
+ TLS_DHE_DSS_WITH_AES_256_CBC_SHA,
+ TLS_DHE_RSA_WITH_AES_256_CBC_SHA,
+ TLS_DH_anon_WITH_AES_256_CBC_SHA,
+ SSL_NO_SUCH_CIPHERSUITE
+};
+const SSLCipherSuite suitesDHAnon[] = {
+ SSL_DH_anon_WITH_RC4_128_MD5,
+ SSL_DH_anon_WITH_DES_CBC_SHA,
+ SSL_DH_anon_WITH_3DES_EDE_CBC_SHA,
+ SSL_DH_anon_EXPORT_WITH_RC4_40_MD5,
+ SSL_DH_anon_EXPORT_WITH_DES40_CBC_SHA,
+ TLS_DH_anon_WITH_AES_128_CBC_SHA,
+ TLS_DH_anon_WITH_AES_256_CBC_SHA,
+ SSL_NO_SUCH_CIPHERSUITE
+};
+const SSLCipherSuite suitesDH_RSA[] = {
+ SSL_DH_RSA_WITH_DES_CBC_SHA,
+ SSL_DH_RSA_WITH_3DES_EDE_CBC_SHA,
+ SSL_DHE_RSA_WITH_DES_CBC_SHA,
+ SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA,
+ SSL_DH_RSA_EXPORT_WITH_DES40_CBC_SHA,
+ SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA,
+ TLS_DH_RSA_WITH_AES_128_CBC_SHA,
+ TLS_DHE_RSA_WITH_AES_128_CBC_SHA,
+ TLS_DH_RSA_WITH_AES_256_CBC_SHA,
+ TLS_DHE_RSA_WITH_AES_256_CBC_SHA,
+ SSL_NO_SUCH_CIPHERSUITE
+};
+const SSLCipherSuite suitesDH_DSS[] = {
+ SSL_DH_DSS_WITH_DES_CBC_SHA,
+ SSL_DH_DSS_WITH_3DES_EDE_CBC_SHA,
+ SSL_DHE_DSS_WITH_DES_CBC_SHA,
+ SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA,
+ SSL_DH_DSS_EXPORT_WITH_DES40_CBC_SHA,
+ SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA,
+ TLS_DH_DSS_WITH_AES_128_CBC_SHA,
+ TLS_DHE_DSS_WITH_AES_128_CBC_SHA,
+ TLS_DH_DSS_WITH_AES_256_CBC_SHA,
+ TLS_DHE_DSS_WITH_AES_256_CBC_SHA,
+ SSL_NO_SUCH_CIPHERSUITE
+};
+const SSLCipherSuite suites_SHA1[] = {
+ SSL_RSA_WITH_RC4_128_SHA,
+ SSL_RSA_EXPORT_WITH_DES40_CBC_SHA,
+ SSL_RSA_WITH_IDEA_CBC_SHA,
+ SSL_RSA_EXPORT_WITH_DES40_CBC_SHA,
+ SSL_RSA_WITH_DES_CBC_SHA,
+ SSL_RSA_WITH_3DES_EDE_CBC_SHA,
+ SSL_DH_DSS_EXPORT_WITH_DES40_CBC_SHA,
+ SSL_DH_DSS_WITH_DES_CBC_SHA,
+ SSL_DH_DSS_WITH_3DES_EDE_CBC_SHA,
+ SSL_DH_RSA_EXPORT_WITH_DES40_CBC_SHA,
+ SSL_DH_RSA_WITH_DES_CBC_SHA,
+ SSL_DH_RSA_WITH_3DES_EDE_CBC_SHA,
+ SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA,
+ SSL_DHE_DSS_WITH_DES_CBC_SHA,
+ SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA,
+ SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA,
+ SSL_DHE_RSA_WITH_DES_CBC_SHA,
+ SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA,
+ SSL_DH_anon_EXPORT_WITH_DES40_CBC_SHA,
+ SSL_DH_anon_WITH_DES_CBC_SHA,
+ SSL_DH_anon_WITH_3DES_EDE_CBC_SHA,
+ SSL_FORTEZZA_DMS_WITH_NULL_SHA,
+ SSL_FORTEZZA_DMS_WITH_FORTEZZA_CBC_SHA,
+ TLS_RSA_WITH_AES_128_CBC_SHA,
+ TLS_DH_DSS_WITH_AES_128_CBC_SHA,
+ TLS_DH_RSA_WITH_AES_128_CBC_SHA,
+ TLS_DHE_DSS_WITH_AES_128_CBC_SHA,
+ TLS_DHE_RSA_WITH_AES_128_CBC_SHA,
+ TLS_DH_anon_WITH_AES_128_CBC_SHA,
+ TLS_RSA_WITH_AES_256_CBC_SHA,
+ TLS_DH_DSS_WITH_AES_256_CBC_SHA,
+ TLS_DH_RSA_WITH_AES_256_CBC_SHA,
+ TLS_DHE_DSS_WITH_AES_256_CBC_SHA,
+ TLS_DHE_RSA_WITH_AES_256_CBC_SHA,
+ TLS_DH_anon_WITH_AES_256_CBC_SHA,
+ SSL_NO_SUCH_CIPHERSUITE
+};
+const SSLCipherSuite suites_MD5[] = {
+ SSL_RSA_EXPORT_WITH_RC4_40_MD5,
+ SSL_RSA_WITH_RC4_128_MD5,
+ SSL_RSA_EXPORT_WITH_RC2_CBC_40_MD5,
+ SSL_DH_anon_EXPORT_WITH_RC4_40_MD5,
+ SSL_DH_anon_WITH_RC4_128_MD5,
+ SSL_NO_SUCH_CIPHERSUITE
+};
+const SSLCipherSuite suites_NULL[] = {
+ SSL_RSA_WITH_NULL_MD5,
+ SSL_NO_SUCH_CIPHERSUITE
+};
+
+const SSLCipherSuite suites_ECDHE[] = {
+ TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,
+ TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA,
+ TLS_ECDHE_ECDSA_WITH_RC4_128_SHA,
+ TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA,
+ TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
+ TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,
+ TLS_ECDHE_RSA_WITH_RC4_128_SHA,
+ TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA,
+ SSL_NO_SUCH_CIPHERSUITE
+};
+
+const SSLCipherSuite suites_ECDH[] = {
+ TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA,
+ TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA,
+ TLS_ECDH_ECDSA_WITH_RC4_128_SHA,
+ TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA,
+ TLS_ECDH_RSA_WITH_AES_128_CBC_SHA,
+ TLS_ECDH_RSA_WITH_AES_256_CBC_SHA,
+ TLS_ECDH_RSA_WITH_RC4_128_SHA,
+ TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA,
+ SSL_NO_SUCH_CIPHERSUITE
+};
+
+/*
+ * Given an SSLContextRef and an array of SSLCipherSuites, terminated by
+ * SSL_NO_SUCH_CIPHERSUITE, select those SSLCipherSuites which the library
+ * supports and do a SSLSetEnabledCiphers() specifying those.
+ */
+OSStatus sslSetEnabledCiphers(
+ SSLContextRef ctx,
+ const SSLCipherSuite *ciphers)
+{
+ size_t numSupported;
+ OSStatus ortn;
+ SSLCipherSuite *supported = NULL;
+ SSLCipherSuite *enabled = NULL;
+ unsigned enabledDex = 0; // index into enabled
+ unsigned supportedDex = 0; // index into supported
+ unsigned inDex = 0; // index into ciphers
+
+ /* first get all the supported ciphers */
+ ortn = SSLGetNumberSupportedCiphers(ctx, &numSupported);
+ if(ortn) {
+ printSslErrStr("SSLGetNumberSupportedCiphers", ortn);
+ return ortn;
+ }
+ supported = (SSLCipherSuite *)malloc(numSupported * sizeof(SSLCipherSuite));
+ ortn = SSLGetSupportedCiphers(ctx, supported, &numSupported);
+ if(ortn) {
+ printSslErrStr("SSLGetSupportedCiphers", ortn);
+ return ortn;
+ }
+
+ /*
+ * Malloc an array we'll use for SSLGetEnabledCiphers - this will be
+ * bigger than the number of suites we actually specify
+ */
+ enabled = (SSLCipherSuite *)malloc(numSupported * sizeof(SSLCipherSuite));
+
+ /*
+ * For each valid suite in ciphers, see if it's in the list of
+ * supported ciphers. If it is, add it to the list of ciphers to be
+ * enabled.
+ */
+ for(inDex=0; ciphers[inDex] != SSL_NO_SUCH_CIPHERSUITE; inDex++) {
+ for(supportedDex=0; supportedDex<numSupported; supportedDex++) {
+ if(ciphers[inDex] == supported[supportedDex]) {
+ enabled[enabledDex++] = ciphers[inDex];
+ break;
+ }
+ }
+ }
+
+ /* send it on down. */
+ ortn = SSLSetEnabledCiphers(ctx, enabled, enabledDex);
+ if(ortn) {
+ printSslErrStr("SSLSetEnabledCiphers", ortn);
+ }
+ free(enabled);
+ free(supported);
+ return ortn;
+}
+
+/*
+ * Specify a restricted set of cipherspecs.
+ */
+OSStatus sslSetCipherRestrictions(
+ SSLContextRef ctx,
+ char cipherRestrict)
+{
+ OSStatus ortn;
+
+ if(cipherRestrict == '\0') {
+ return errSecSuccess; // actually should not have been called
+ }
+ switch(cipherRestrict) {
+ case 'e':
+ ortn = sslSetEnabledCiphers(ctx, suites40);
+ break;
+ case 'd':
+ ortn = sslSetEnabledCiphers(ctx, suitesDES);
+ break;
+ case 'D':
+ ortn = sslSetEnabledCiphers(ctx, suitesDES40);
+ break;
+ case '3':
+ ortn = sslSetEnabledCiphers(ctx, suites3DES);
+ break;
+ case '4':
+ ortn = sslSetEnabledCiphers(ctx, suitesRC4);
+ break;
+ case '$':
+ ortn = sslSetEnabledCiphers(ctx, suitesRC4_40);
+ break;
+ case '2':
+ ortn = sslSetEnabledCiphers(ctx, suitesRC2);
+ break;
+ case 'a':
+ ortn = sslSetEnabledCiphers(ctx, suitesAES128);
+ break;
+ case 'A':
+ ortn = sslSetEnabledCiphers(ctx, suitesAES256);
+ break;
+ case 'h':
+ ortn = sslSetEnabledCiphers(ctx, suitesDH);
+ break;
+ case 'H':
+ ortn = sslSetEnabledCiphers(ctx, suitesDHAnon);
+ break;
+ case 'r':
+ ortn = sslSetEnabledCiphers(ctx, suitesDH_RSA);
+ break;
+ case 's':
+ ortn = sslSetEnabledCiphers(ctx, suitesDH_DSS);
+ break;
+ case 'n':
+ ortn = sslSetEnabledCiphers(ctx, suites_NULL);
+ break;
+ case 'E':
+ ortn = sslSetEnabledCiphers(ctx, suites_ECDHE);
+ break;
+ case 'F':
+ ortn = sslSetEnabledCiphers(ctx, suites_ECDH);
+ break;
+ default:
+ printf("***bad cipherSpec***\n");
+ exit(1);
+ }
+ return ortn;
+}
+
+#if 0
+int sslVerifyClientCertState(
+ const char *whichSide, // "client" or "server"
+ SSLClientCertificateState expectState,
+ SSLClientCertificateState gotState)
+{
+ if(expectState == SSL_CLIENT_CERT_IGNORE) {
+ /* app says "don't bother checking" */
+ return 0;
+ }
+ if(expectState == gotState) {
+ return 0;
+ }
+ printf("***%s: Expected clientCertState %s; got %s\n", whichSide,
+ sslGetClientCertStateString(expectState),
+ sslGetClientCertStateString(gotState));
+ return 1;
+}
+
+int sslVerifyRtn(
+ char *whichSide, // "client" or "server"
+ OSStatus expectRtn,
+ OSStatus gotRtn)
+{
+ if(expectRtn == gotRtn) {
+ return 0;
+ }
+ printf("***%s: Expected return %s; got %s\n", whichSide,
+ sslGetSSLErrString(expectRtn),
+ sslGetSSLErrString(gotRtn));
+ return 1;
+}
+
+int sslVerifyProtVers(
+ char *whichSide, // "client" or "server"
+ SSLProtocol expectProt,
+ SSLProtocol gotProt)
+{
+ if(expectProt == SSL_PROTOCOL_IGNORE) {
+ /* app says "don't bopther checking" */
+ return 0;
+ }
+ if(expectProt == gotProt) {
+ return 0;
+ }
+ printf("***%s: Expected return %s; got %s\n", whichSide,
+ sslGetProtocolVersionString(expectProt),
+ sslGetProtocolVersionString(gotProt));
+ return 1;
+}
+
+int sslVerifyCipher(
+ char *whichSide, // "client" or "server"
+ SSLCipherSuite expectCipher,
+ SSLCipherSuite gotCipher)
+{
+ if(expectCipher == SSL_CIPHER_IGNORE) {
+ /* app says "don't bopther checking" */
+ return 0;
+ }
+ if(expectCipher == gotCipher) {
+ return 0;
+ }
+ printf("***%s: Expected return %s; got %s\n", whichSide,
+ sslGetCipherSuiteString(expectCipher),
+ sslGetCipherSuiteString(gotCipher));
+ return 1;
+}
+
+
+OSStatus sslSetProtocols(
+ SSLContextRef ctx,
+ const char *acceptedProts,
+ SSLProtocol tryVersion) // only used if acceptedProts NULL
+{
+ OSStatus ortn;
+
+ if(acceptedProts) {
+ ortn = SSLSetProtocolVersionEnabled(ctx, kSSLProtocolAll, false);
+ if(ortn) {
+ printSslErrStr("SSLSetProtocolVersionEnabled(all off)", ortn);
+ return ortn;
+ }
+ for(const char *cp = acceptedProts; *cp; cp++) {
+ SSLProtocol prot;
+ switch(*cp) {
+ case '2':
+ prot = kSSLProtocol2;
+ break;
+ case '3':
+ prot = kSSLProtocol3;
+ break;
+ case 't':
+ prot = kTLSProtocol1;
+ break;
+ default:
+ printf("***BRRZAP! Bad acceptedProts string %s. Aborting.\n", acceptedProts);
+ exit(1);
+ }
+ ortn = SSLSetProtocolVersionEnabled(ctx, prot, true);
+ if(ortn) {
+ printSslErrStr("SSLSetProtocolVersionEnabled", ortn);
+ return ortn;
+ }
+ }
+ }
+ else {
+ ortn = SSLSetProtocolVersion(ctx, tryVersion);
+ if(ortn) {
+ printSslErrStr("SSLSetProtocolVersion", ortn);
+ return ortn;
+ }
+ }
+ return errSecSuccess;
+}
+
+void sslShowResult(
+ const char *whichSide, // "client" or "server"
+ SslAppTestParams *params)
+{
+ printf("%s status:\n", whichSide);
+ if(params->acceptedProts) {
+ printf(" Allowed SSL versions : %s\n", params->acceptedProts);
+ }
+ else {
+ printf(" Attempted SSL version : %s\n",
+ sslGetProtocolVersionString(params->tryVersion));
+ }
+ printf(" Result : %s\n", sslGetSSLErrString(params->ortn));
+ printf(" Negotiated SSL version : %s\n",
+ sslGetProtocolVersionString(params->negVersion));
+ printf(" Negotiated CipherSuite : %s\n",
+ sslGetCipherSuiteString(params->negCipher));
+ if(params->certState != kSSLClientCertNone) {
+ printf(" Client Cert State : %s\n",
+ sslGetClientCertStateString(params->certState));
+ }
+}
+#endif
+
+/* print a '.' every few seconds to keep UI alive while connecting */
+static CFAbsoluteTime lastTime = (CFAbsoluteTime)0.0;
+#define TIME_INTERVAL 3.0
+
+void sslOutputDot()
+{
+ CFAbsoluteTime thisTime = CFAbsoluteTimeGetCurrent();
+
+ // throttle down.
+ usleep(1000);
+
+ if(lastTime == 0.0) {
+ /* avoid printing first time thru */
+ lastTime = thisTime;
+ return;
+ }
+ if((thisTime - lastTime) >= TIME_INTERVAL) {
+ printf("."); fflush(stdout);
+ lastTime = thisTime;
+ }
+}
+
+#if 0
+/* main server pthread body */
+static void *sslServerThread(void *arg)
+{
+ SslAppTestParams *testParams = (SslAppTestParams *)arg;
+ OSStatus status;
+
+ status = sslAppServe(testParams);
+ pthread_exit((void*)status);
+ /* NOT REACHED */
+ return (void *)status;
+}
+
+/*
+ * Run one session, with the server in a separate thread.
+ * On entry, serverParams->port is the port we attempt to run on;
+ * the server thread may overwrite that with a different port if it's
+ * unable to open the port we specify. Whatever is left in
+ * serverParams->port is what's used for the client side.
+ */
+#define CLIENT_WAIT_SECONDS 1
+int sslRunSession(
+ SslAppTestParams*serverParams,
+ SslAppTestParams *clientParams,
+ const char *testDesc)
+{
+ pthread_t serverPthread;
+ OSStatus clientRtn;
+ void *serverRtn;
+
+ if(testDesc && !clientParams->quiet) {
+ printf("===== %s =====\n", testDesc);
+ }
+
+ if(pthread_mutex_init(&serverParams->pthreadMutex, NULL)) {
+ printf("***Error initializing mutex; aborting.\n");
+ return -1;
+ }
+ if(pthread_cond_init(&serverParams->pthreadCond, NULL)) {
+ printf("***Error initializing pthreadCond; aborting.\n");
+ return -1;
+ }
+ serverParams->serverReady = false; // server sets true
+
+ int result = pthread_create(&serverPthread, NULL,
+ sslServerThread, serverParams);
+ if(result) {
+ printf("***Error starting up server thread; aborting.\n");
+ return result;
+ }
+
+ /* wait for server to set up a socket we can connect to */
+ if(pthread_mutex_lock(&serverParams->pthreadMutex)) {
+ printf("***Error acquiring server lock; aborting.\n");
+ return -1;
+ }
+ while(!serverParams->serverReady) {
+ if(pthread_cond_wait(&serverParams->pthreadCond, &serverParams->pthreadMutex)) {
+ printf("***Error waiting server thread; aborting.\n");
+ return -1;
+ }
+ }
+ pthread_mutex_unlock(&serverParams->pthreadMutex);
+ pthread_cond_destroy(&serverParams->pthreadCond);
+ pthread_mutex_destroy(&serverParams->pthreadMutex);
+
+ clientParams->port = serverParams->port;
+ clientRtn = sslAppClient(clientParams);
+ /* server doesn't shut down its socket until it sees this */
+ serverParams->clientDone = 1;
+ result = pthread_join(serverPthread, &serverRtn);
+ if(result) {
+ printf("***pthread_join returned %d, aborting\n", result);
+ return result;
+ }
+
+ if(serverParams->verbose) {
+ sslShowResult("server", serverParams);
+ }
+ if(clientParams->verbose) {
+ sslShowResult("client", clientParams);
+ }
+
+ /* verify results */
+ int ourRtn = 0;
+ ourRtn += sslVerifyRtn("server", serverParams->expectRtn, serverParams->ortn);
+ ourRtn += sslVerifyRtn("client", clientParams->expectRtn, clientParams->ortn);
+ ourRtn += sslVerifyProtVers("server", serverParams->expectVersion,
+ serverParams->negVersion);
+ ourRtn += sslVerifyProtVers("client", clientParams->expectVersion,
+ clientParams->negVersion);
+ ourRtn += sslVerifyClientCertState("server", serverParams->expectCertState,
+ serverParams->certState);
+ ourRtn += sslVerifyClientCertState("client", clientParams->expectCertState,
+ clientParams->certState);
+ if(serverParams->ortn == errSecSuccess) {
+ ourRtn += sslVerifyCipher("server", serverParams->expectCipher,
+ serverParams->negCipher);
+ }
+ if(clientParams->ortn == errSecSuccess) {
+ ourRtn += sslVerifyCipher("client", clientParams->expectCipher,
+ clientParams->negCipher);
+ }
+ return ourRtn;
+}
+
+/*
+ * Add all of the roots in a given KC to SSL ctx's trusted anchors.
+ */
+OSStatus sslAddTrustedRoots(
+ SSLContextRef ctx,
+ SecKeychainRef keychain,
+ bool *foundOne) // RETURNED, true if we found
+ // at least one root cert
+{
+ OSStatus ortn;
+ SecCertificateRef secCert;
+ SecKeychainSearchRef srch;
+
+ *foundOne = false;
+ ortn = SecKeychainSearchCreateFromAttributes(keychain,
+ kSecCertificateItemClass,
+ NULL, // any attrs
+ &srch);
+ if(ortn) {
+ printSslErrStr("SecKeychainSearchCreateFromAttributes", ortn);
+ return ortn;
+ }
+
+ /*
+ * Only use root certs. Not an error if we don't find any.
+ */
+ do {
+ ortn = SecKeychainSearchCopyNext(srch,
+ (SecKeychainItemRef *)&secCert);
+ if(ortn) {
+ break;
+ }
+
+ /* see if it's a root */
+ if(!isCertRoot(secCert)) {
+ continue;
+ }
+
+ /* Tell Secure Transport to trust this one. */
+ ortn = addTrustedSecCert(ctx, secCert, false);
+ if(ortn) {
+ /* fatal */
+ printSslErrStr("addTrustedSecCert", ortn);
+ return ortn;
+ }
+ CFRelease(secCert);
+ *foundOne = true;
+ } while(ortn == errSecSuccess);
+ CFRelease(srch);
+ return errSecSuccess;
+}
+
+/*
+ * Wrapper for sslIdentPicker, with optional trusted anchor specified as a filename.
+ */
+OSStatus sslIdentityPicker(
+ SecKeychainRef kcRef, // NULL means use default list
+ const char *trustedAnchor, // optional additional trusted anchor
+ bool includeRoot, // true --> root is appended to outArray
+ // false --> root not included
+ CFArrayRef *outArray) // created and RETURNED
+{
+ SecCertificateRef trustedCert = NULL;
+ OSStatus ortn;
+
+ if(trustedAnchor) {
+ ortn = sslReadAnchor(trustedAnchor, &trustedCert);
+ if(ortn) {
+ printf("***Error reading %s. sslIdentityPicker proceeding with no anchor.\n",
+ trustedAnchor);
+ trustedCert = NULL;
+ }
+ }
+ ortn = sslIdentPicker(kcRef, trustedCert, includeRoot, outArray);
+ if(trustedCert) {
+ CFRelease(trustedCert);
+ }
+ return ortn;
+}
+
+/*
+ * Given a keychain name, convert it into a full path using the "SSL regression
+ * test suite algorithm". The Sec layer by default locates root root's keychains
+ * in different places depending on whether we're actually logged in as root
+ * or running via e.g. cron, so we force the location of root keychains to
+ * a hard-coded path. User keychain names we leave alone.
+ */
+void sslKeychainPath(
+ const char *kcName,
+ char *kcPath) // allocd by caller, MAXPATHLEN
+{
+ if(kcName[0] == '\0') {
+ kcPath[0] = '\0';
+ }
+ else if(geteuid() == 0) {
+ /* root */
+ sprintf(kcPath, "/Library/Keychains/%s", kcName);
+ }
+ else {
+ /* user, leave alone */
+ strcpy(kcPath, kcName);
+ }
+}
+
+/* Verify presence of required file. Returns nonzero if not found. */
+int sslCheckFile(const char *path)
+{
+ struct stat sb;
+
+ if(stat(path, &sb)) {
+ printf("***Can't find file %s.\n", path);
+ printf(" Try running in the build directory, perhaps after running the\n"
+ " makeLocalCert script.\n");
+ return 1;
+ }
+ return 0;
+}
+
+#endif
+
+/* Stringify a SSL_ECDSA_NamedCurve */
+extern const char *sslCurveString(
+ SSL_ECDSA_NamedCurve namedCurve)
+{
+ static char unk[100];
+
+ switch(namedCurve) {
+ case SSL_Curve_None: return "Curve_None";
+ case SSL_Curve_secp256r1: return "secp256r1";
+ case SSL_Curve_secp384r1: return "secp384r1";
+ case SSL_Curve_secp521r1: return "secp521r1";
+ default:
+ sprintf(unk, "Unknown <%d>", (int)namedCurve);
+ return unk;
+ }
+}