aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/core/security/MCCertificateUtils.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/core/security/MCCertificateUtils.cpp')
-rw-r--r--src/core/security/MCCertificateUtils.cpp162
1 files changed, 162 insertions, 0 deletions
diff --git a/src/core/security/MCCertificateUtils.cpp b/src/core/security/MCCertificateUtils.cpp
new file mode 100644
index 00000000..42b75916
--- /dev/null
+++ b/src/core/security/MCCertificateUtils.cpp
@@ -0,0 +1,162 @@
+//
+// MCCertificateUtils.cc
+// mailcore2
+//
+// Created by DINH Viêt Hoà on 7/25/13.
+// Copyright (c) 2013 MailCore. All rights reserved.
+//
+
+#include "MCCertificateUtils.h"
+
+#if __APPLE__
+#include <CoreFoundation/CoreFoundation.h>
+#include <Security/Security.h>
+#else
+#include <openssl/bio.h>
+#include <openssl/x509.h>
+#include <openssl/x509_vfy.h>
+#include <openssl/pem.h>
+#include <openssl/err.h>
+#endif
+
+#include "MCLog.h"
+
+bool mailcore::checkCertificate(mailstream * stream, String * hostname)
+{
+#if __APPLE__
+ bool result = false;
+ CFStringRef hostnameCFString;
+ SecPolicyRef policy;
+ CFMutableArrayRef certificates;
+ SecTrustRef trust = NULL;
+ SecTrustResultType trustResult;
+ OSStatus status;
+
+ carray * cCerts = mailstream_get_certificate_chain(stream);
+ if (cCerts == NULL) {
+ fprintf(stderr, "warning: No certificate chain retrieved");
+ goto err;
+ }
+
+ hostnameCFString = CFStringCreateWithCharacters(NULL, (const UniChar *) hostname->unicodeCharacters(),
+ hostname->length());
+ policy = SecPolicyCreateSSL(true, hostnameCFString);
+ certificates = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
+
+ for(unsigned int i = 0 ; i < carray_count(cCerts) ; i ++) {
+ MMAPString * str;
+ str = (MMAPString *) carray_get(cCerts, i);
+ CFDataRef data = CFDataCreate(NULL, (const UInt8 *) str->str, (CFIndex) str->len);
+ SecCertificateRef cert = SecCertificateCreateWithData(NULL, data);
+ CFArrayAppendValue(certificates, cert);
+ CFRelease(data);
+ CFRelease(cert);
+ }
+
+ static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
+
+ // The below API calls are not thread safe. We're making sure not to call the concurrently.
+ pthread_mutex_lock(&lock);
+
+ status = SecTrustCreateWithCertificates(certificates, policy, &trust);
+ if (status != noErr) {
+ pthread_mutex_unlock(&lock);
+ goto free_certs;
+ }
+
+ status = SecTrustEvaluate(trust, &trustResult);
+ if (status != noErr) {
+ pthread_mutex_unlock(&lock);
+ goto free_certs;
+ }
+
+ pthread_mutex_unlock(&lock);
+
+ switch (trustResult) {
+ case kSecTrustResultUnspecified:
+ case kSecTrustResultProceed:
+ // certificate chain is ok
+ result = true;
+ break;
+
+ default:
+ // certificate chain is invalid
+ break;
+ }
+
+ CFRelease(trust);
+free_certs:
+ CFRelease(certificates);
+ mailstream_certificate_chain_free(cCerts);
+ CFRelease(policy);
+ CFRelease(hostnameCFString);
+err:
+ return result;
+#else
+ bool result = false;
+ X509_STORE * store = NULL;
+ X509_STORE_CTX * storectx = NULL;
+ STACK_OF(X509) * certificates = NULL;
+ int status;
+
+ carray * cCerts = mailstream_get_certificate_chain(stream);
+ if (cCerts == NULL) {
+ fprintf(stderr, "warning: No certificate chain retrieved");
+ goto err;
+ }
+
+ store = X509_STORE_new();
+ if (store == NULL) {
+ goto free_certs;
+ }
+
+ status = X509_STORE_set_default_paths(store);
+ if (status != 1) {
+ printf("Error loading the system-wide CA certificates");
+ }
+
+ certificates = sk_X509_new_null();
+ for(unsigned int i = 0 ; i < carray_count(cCerts) ; i ++) {
+ MMAPString * str;
+ str = (MMAPString *) carray_get(cCerts, i);
+ if (str == NULL) {
+ goto free_certs;
+ }
+ BIO *bio = BIO_new_mem_buf((void *) str->str, str->len);
+ X509 *certificate = d2i_X509_bio(bio, NULL);
+ BIO_free(bio);
+ if (!sk_X509_push(certificates, certificate)) {
+ goto free_certs;
+ }
+ }
+
+ storectx = X509_STORE_CTX_new();
+ if (storectx == NULL) {
+ goto free_certs;
+ }
+
+ status = X509_STORE_CTX_init(storectx, store, sk_X509_value(certificates, 0), certificates);
+ if (status != 1) {
+ goto free_certs;
+ }
+
+ status = X509_verify_cert(storectx);
+ if (status == 1) {
+ result = true;
+ }
+
+free_certs:
+ mailstream_certificate_chain_free(cCerts);
+ if (certificates != NULL) {
+ sk_X509_pop_free((STACK_OF(X509) *) certificates, X509_free);
+ }
+ if (storectx != NULL) {
+ X509_STORE_CTX_free(storectx);
+ }
+ if (store != NULL) {
+ X509_STORE_free(store);
+ }
+err:
+ return result;
+#endif
+}