X-Git-Url: https://git.saurik.com/apple/security.git/blobdiff_plain/b04fe171f0375ecd5d8a24747ca1dff85720a0ca..6b200bc335dc93c5516ccb52f14bd896d8c7fad7:/SecurityTests/clxutils/clAppUtils/sslAppUtils.cpp?ds=sidebyside diff --git a/SecurityTests/clxutils/clAppUtils/sslAppUtils.cpp b/SecurityTests/clxutils/clAppUtils/sslAppUtils.cpp deleted file mode 100644 index 69b15508..00000000 --- a/SecurityTests/clxutils/clAppUtils/sslAppUtils.cpp +++ /dev/null @@ -1,1653 +0,0 @@ - -#include "sslAppUtils.h" -#include "sslThreading.h" -#include "identPicker.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include // for Sec errors -#include - -/* Set true when PR-3074739 is merged to TOT */ -#define NEW_SSL_ERRS_3074739 1 - -const char *sslGetCipherSuiteString(SSLCipherSuite cs) -{ - static char noSuite[40]; - - switch(cs) { - case SSL_NULL_WITH_NULL_NULL: - return "SSL_NULL_WITH_NULL_NULL"; - case SSL_RSA_WITH_NULL_MD5: - return "SSL_RSA_WITH_NULL_MD5"; - case SSL_RSA_WITH_NULL_SHA: - return "SSL_RSA_WITH_NULL_SHA"; - case SSL_RSA_EXPORT_WITH_RC4_40_MD5: - return "SSL_RSA_EXPORT_WITH_RC4_40_MD5"; - case SSL_RSA_WITH_RC4_128_MD5: - return "SSL_RSA_WITH_RC4_128_MD5"; - case SSL_RSA_WITH_RC4_128_SHA: - return "SSL_RSA_WITH_RC4_128_SHA"; - case SSL_RSA_EXPORT_WITH_RC2_CBC_40_MD5: - return "SSL_RSA_EXPORT_WITH_RC2_CBC_40_MD5"; - case SSL_RSA_WITH_IDEA_CBC_SHA: - return "SSL_RSA_WITH_IDEA_CBC_SHA"; - case SSL_RSA_EXPORT_WITH_DES40_CBC_SHA: - return "SSL_RSA_EXPORT_WITH_DES40_CBC_SHA"; - case SSL_RSA_WITH_DES_CBC_SHA: - return "SSL_RSA_WITH_DES_CBC_SHA"; - case SSL_RSA_WITH_3DES_EDE_CBC_SHA: - return "SSL_RSA_WITH_3DES_EDE_CBC_SHA"; - case SSL_DH_DSS_EXPORT_WITH_DES40_CBC_SHA: - return "SSL_DH_DSS_EXPORT_WITH_DES40_CBC_SHA"; - case SSL_DH_DSS_WITH_DES_CBC_SHA: - return "SSL_DH_DSS_WITH_DES_CBC_SHA"; - case SSL_DH_DSS_WITH_3DES_EDE_CBC_SHA: - return "SSL_DH_DSS_WITH_3DES_EDE_CBC_SHA"; - case SSL_DH_RSA_EXPORT_WITH_DES40_CBC_SHA: - return "SSL_DH_RSA_EXPORT_WITH_DES40_CBC_SHA"; - case SSL_DH_RSA_WITH_DES_CBC_SHA: - return "SSL_DH_RSA_WITH_DES_CBC_SHA"; - case SSL_DH_RSA_WITH_3DES_EDE_CBC_SHA: - return "SSL_DH_RSA_WITH_3DES_EDE_CBC_SHA"; - case SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA: - return "SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA"; - case SSL_DHE_DSS_WITH_DES_CBC_SHA: - return "SSL_DHE_DSS_WITH_DES_CBC_SHA"; - case SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA: - return "SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA"; - case SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA: - return "SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA"; - case SSL_DHE_RSA_WITH_DES_CBC_SHA: - return "SSL_DHE_RSA_WITH_DES_CBC_SHA"; - case SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA: - return "SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA"; - case SSL_DH_anon_EXPORT_WITH_RC4_40_MD5: - return "SSL_DH_anon_EXPORT_WITH_RC4_40_MD5"; - case SSL_DH_anon_WITH_RC4_128_MD5: - return "SSL_DH_anon_WITH_RC4_128_MD5"; - case SSL_DH_anon_EXPORT_WITH_DES40_CBC_SHA: - return "SSL_DH_anon_EXPORT_WITH_DES40_CBC_SHA"; - case SSL_DH_anon_WITH_DES_CBC_SHA: - return "SSL_DH_anon_WITH_DES_CBC_SHA"; - case SSL_DH_anon_WITH_3DES_EDE_CBC_SHA: - return "SSL_DH_anon_WITH_3DES_EDE_CBC_SHA"; - 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"; - case SSL_RSA_WITH_RC2_CBC_MD5: - return "SSL_RSA_WITH_RC2_CBC_MD5"; - case SSL_RSA_WITH_IDEA_CBC_MD5: - return "SSL_RSA_WITH_IDEA_CBC_MD5"; - case SSL_RSA_WITH_DES_CBC_MD5: - return "SSL_RSA_WITH_DES_CBC_MD5"; - case SSL_RSA_WITH_3DES_EDE_CBC_MD5: - return "SSL_RSA_WITH_3DES_EDE_CBC_MD5"; - case SSL_NO_SUCH_CIPHERSUITE: - return "SSL_NO_SUCH_CIPHERSUITE"; - 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 */ - 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"; - - default: - sprintf(noSuite, "Unknown (%d)", (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"; - default: - sprintf(noProt, "Unknown (%d)", (unsigned)prot); - return noProt; - } -} - -/* - * Return string representation of SecureTransport-related OSStatus. - */ -const char *sslGetSSLErrString(OSStatus err) -{ - static char noErrStr[20]; - - switch(err) { - case noErr: - return "noErr"; - case memFullErr: - return "memFullErr"; - case paramErr: - return "paramErr"; - case unimpErr: - return "unimpErr"; - case ioErr: - return "ioErr"; - case badReqErr: - return "badReqErr"; - 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 errSecReadOnly: return "errSecReadOnly"; - case errSecAuthFailed: return "errSecAuthFailed"; - case errSecNoSuchKeychain: return "errSecNoSuchKeychain"; - case errSecInvalidKeychain: return "errSecInvalidKeychain"; - case errSecDuplicateItem: return "errSecDuplicateItem"; - case errSecItemNotFound: return "errSecItemNotFound"; - 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 errSessionInvalidId: return "errSessionInvalidId"; - case errSessionInvalidAttributes: return "errSessionInvalidAttributes"; - case errSessionAuthorizationDenied: return "errSessionAuthorizationDenied"; - case errSessionInternal: return "errSessionInternal"; - case errSessionInvalidFlags: return "errSessionInvalidFlags"; - case errSecInvalidTrustSettings: return "errSecInvalidTrustSettings"; - case errSecNoTrustSettings: return "errSecNoTrustSettings"; - - default: - if(err < (CSSM_BASE_ERROR + - (CSSM_ERRORCODE_MODULE_EXTENT * 8))) { - /* assume CSSM error */ - return cssmErrToStr(err); - } - else { - sprintf(noErrStr, "Unknown (%d)", (unsigned)err); - return noErrStr; - } - } -} - -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 - CSSM_BOOL encryptOnly, - CSSM_BOOL completeCertChain, - const char *anchorFile, // optional trusted anchor - SecKeychainRef *pKcRef) // RETURNED -{ - 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, - NULL, // SSL policy - anchorFile); -} - -/* - * 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) -{ - /* 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; - bool brtn = false; - - 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); - return brtn; -} - - -/* - * 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 - const CSSM_OID *vfyPolicy, // optional - if NULL, use SSL - 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 noErr; - } - - /* - * 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 SSL cert chain verification */ - ortn = SecPolicySearchCreate(CSSM_CERT_X_509v3, - vfyPolicy ? vfyPolicy : &CSSMOID_APPLE_TP_SSL, - 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 = noErr; - 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 = noErr; - goto errOut; - } - if(!includeRoot) { - /* skip the last (root) cert) */ - numResCerts--; - } - for(CFIndex dex=1; dexacceptedProts) { - 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)); - } -} - -/* 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(); - - if(lastTime == 0.0) { - /* avoid printing first time thru */ - lastTime = thisTime; - return; - } - if((thisTime - lastTime) >= TIME_INTERVAL) { - printf("."); fflush(stdout); - lastTime = thisTime; - } -} - -/* 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); - } - - /* - * Workaround for Radar 4619502: resolve references to Security.framework - * here, in main thread, before we fork off the server thread. - */ - SecKeychainRef defaultKc = NULL; - SecKeychainCopyDefault(&defaultKc); - /* end workaround */ - - 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 == noErr) { - ourRtn += sslVerifyCipher("server", serverParams->expectCipher, - serverParams->negCipher); - } - if(clientParams->ortn == noErr) { - ourRtn += sslVerifyCipher("client", clientParams->expectCipher, - clientParams->negCipher); - } - - if(defaultKc) { - /* for workaround for Radar 4619502 */ - CFRelease(defaultKc); - } - 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(!isCertRefRoot(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 == noErr); - CFRelease(srch); - return noErr; -} - -/* - * 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 - const CSSM_OID *vfyPolicy, // optional - if NULL, use SSL - 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, vfyPolicy, 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. - * This has to be kept in sync with the sslKcSetup script fragment in - * sslScripts. - */ -void sslKeychainPath( - const char *kcName, - char *kcPath) // allocd by caller, MAXPATHLEN -{ - if(kcName[0] == '\0') { - kcPath[0] = '\0'; - } - else if(geteuid() == 0) { - /* root */ - const char *buildDir = getenv("LOCAL_BUILD_DIR"); - if(buildDir == NULL) { - buildDir = ""; - } - sprintf(kcPath, "%s/Library/Keychains/%s", buildDir, 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; -} - -/* 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; - } -} -