Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -265,7 +265,7 @@ var targets: [Target] = [
"unittest.cpp",
"unittest.mm"
],
sources: ["IMAPInterruptCurrentCommandTests.swift", "LibetpanHelperTests.swift", "unittest.swift"],
sources: ["CertificateUtilsTests.swift", "IMAPInterruptCurrentCommandTests.swift", "LibetpanHelperTests.swift", "unittest.swift"],
resources: [
.copy("data")
]
Expand Down
2 changes: 2 additions & 0 deletions configure-headers.sh
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ cp core/basetypes/MCDataStreamDecoder.h ./include/MailCore
cp core/basetypes/MCDefines.h ./include/MailCore
cp core/basetypes/MCMD5.h ./include/MailCore
cp core/basetypes/MCOperationQueueCallback.h ./include/MailCore
cp core/security/MCCertificateUtils.h ./include/MailCore
cp core/basetypes/MCBase64.h ./include/MailCore
cp core/basetypes/MCLock.h ./include/MailCore
cp core/basetypes/MCMainThread.h ./include/MailCore
Expand Down Expand Up @@ -252,3 +253,4 @@ cp c/imap/CIMAPSearchOperation.h ./include/MailCore

cp c/utils/COperation.h ./include/MailCore
cp c/utils/CAutoreleasePool.h ./include/MailCore
cp c/utils/CCertificateUtils.h ./include/MailCore
1 change: 1 addition & 0 deletions src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,7 @@ if(WIN32)
target_link_libraries(CMailCore
PRIVATE
${MAILCORE2_LIB_TARGET}
${LIBETPAN_LIBRARY}
${DISPATCH_LIBRARY}
${DISPATCH_BLOCKS_LIBRARY}
)
Expand Down
49 changes: 49 additions & 0 deletions src/c/utils/CCertificateUtils.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
//
// CCertificateUtils.cpp
// mailcore2
//

#include "CCertificateUtils.h"
#include "CBase+Private.h"

#include <MailCore/MCCertificateUtils.h>
#include <MailCore/MCArray.h>
#include <MailCore/MCData.h>

// Converts an Array of Data into the carray of MMAPString that libetpan uses for
// certificate chains. Free with mailstream_certificate_chain_free().
static carray * certificateChainFromArray(mailcore::Array * array)
{
if (array == NULL) {
return NULL;
}
carray * result = carray_new(array->count() > 0 ? array->count() : 1);
for(unsigned int i = 0 ; i < array->count() ; i ++) {
mailcore::Data * der = (mailcore::Data *) array->objectAtIndex(i);
MMAPString * str = mmap_string_new_len(der->bytes(), (size_t) der->length());
carray_add(result, str, NULL);
}
return result;
}

bool CCertificateUtils_checkCertificateChain(CArray derCertificates,
MailCoreString hostname,
CArray derTrustAnchors,
int64_t verifyTime)
{
carray * cCerts = certificateChainFromArray(derCertificates.instance);
carray * cTrustAnchors = certificateChainFromArray(derTrustAnchors.instance);

bool result = false;
if (cCerts != NULL) {
result = mailcore::checkCertificateChain(cCerts, hostname.instance, cTrustAnchors, (time_t) verifyTime);
}

if (cCerts != NULL) {
mailstream_certificate_chain_free(cCerts);
}
if (cTrustAnchors != NULL) {
mailstream_certificate_chain_free(cTrustAnchors);
}
return result;
}
36 changes: 36 additions & 0 deletions src/c/utils/CCertificateUtils.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
//
// CCertificateUtils.h
// mailcore2
//
// C entry point to mailcore::checkCertificateChain(), so the certificate verification every
// session performs after the TLS handshake can be exercised from Swift unit tests (COR-170).
//

#ifndef MAILCORE_C_CERTIFICATEUTILS_H
#define MAILCORE_C_CERTIFICATEUTILS_H

#include "CBase.h"
#include "CArray.h"
#include "MailCoreString.h"

#ifdef __cplusplus
extern "C" {
#endif

/// Verifies a DER-encoded certificate chain (leaf first, CArray of CData) for `hostname`:
/// the chain must lead to a trusted root and the leaf must be issued for `hostname`, which
/// may be a DNS name or an IPv4/IPv6 literal.
///
/// `derTrustAnchors` (CArray of CData): when its instance is non-NULL these roots are
/// trusted in addition to the system store. `verifyTime`: Unix time to evaluate validity at,
/// 0 means now.
CMAILCORE_EXPORT bool CCertificateUtils_checkCertificateChain(CArray derCertificates,
MailCoreString hostname,
CArray derTrustAnchors,
int64_t verifyTime);

#ifdef __cplusplus
}
#endif

#endif /* MAILCORE_C_CERTIFICATEUTILS_H */
1 change: 1 addition & 0 deletions src/cmake/public-headers.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ set(MAILCORE2_CORE_HEADERS
core/smtp/MCSMTP.h
core/smtp/MCSMTPProgressCallback.h
core/smtp/MCSMTPSession.h
core/security/MCCertificateUtils.h
)

set(MAILCORE2_ASYNC_HEADERS
Expand Down
9 changes: 9 additions & 0 deletions src/core/imap/MCIMAPSession.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -679,7 +679,16 @@ void IMAPSession::connect(ErrorCode * pError)
goto close;
}

#if __APPLE__
r = mailimap_socket_starttls(mImap);
#else
// Passing callback to set the server name into SSL context
// Needed for SNI extension for TLS https://en.wikipedia.org/wiki/Server_Name_Indication
// On Apple platforms libetpan uses CFNetwork instead, that's why callback is not needed
r = mailimap_socket_starttls_with_callback(mImap,
setMailStreamSSLContextServerName,
const_cast<void*>(static_cast<const void*>(MCUTF8(mHostname))));
#endif
if (hasError(r)) {
MCLog("no TLS %i", r);
* pError = ErrorTLSNotAvailable;
Expand Down
17 changes: 17 additions & 0 deletions src/core/nntp/MCNNTPSession.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,12 @@

using namespace mailcore;

#if !__APPLE__
static void setMailStreamSSLContextServerName(mailstream_ssl_context * ssl_context, void * data) {
mailstream_ssl_set_server_name(ssl_context, static_cast<char*>(data));
}
#endif

static int xover_resp_to_fields(struct newsnntp_xover_resp_item * item, struct mailimf_fields ** result);

enum {
Expand Down Expand Up @@ -282,7 +288,18 @@ void NNTPSession::connect(ErrorCode * pError)

case ConnectionTypeTLS:
MCLog("connect %s %u", MCUTF8(hostname()), (unsigned int) port());
#if __APPLE__
r = newsnntp_ssl_connect(mNNTP, MCUTF8(hostname()), port());
#else
// Passing callback to set the server name into SSL context
// Needed for SNI extension for TLS https://en.wikipedia.org/wiki/Server_Name_Indication
// On Apple platforms libetpan uses CFNetwork instead, that's why callback is not needed
r = newsnntp_ssl_connect_with_callback(mNNTP,
MCUTF8(hostname()),
port(),
setMailStreamSSLContextServerName,
const_cast<void*>(static_cast<const void*>(MCUTF8(hostname()))));
#endif
if (r != NEWSNNTP_NO_ERROR) {
* pError = ErrorConnection;
return;
Expand Down
26 changes: 26 additions & 0 deletions src/core/pop/MCPOPSession.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,12 @@

using namespace mailcore;

#if !__APPLE__
static void setMailStreamSSLContextServerName(mailstream_ssl_context * ssl_context, void * data) {
mailstream_ssl_set_server_name(ssl_context, static_cast<char*>(data));
}
#endif

enum {
STATE_DISCONNECTED,
STATE_CONNECTED,
Expand Down Expand Up @@ -223,7 +229,16 @@ void POPSession::connect(ErrorCode * pError)
}

MCLog("start TLS");
#if __APPLE__
r = mailpop3_socket_starttls(mPop);
#else
// Passing callback to set the server name into SSL context
// Needed for SNI extension for TLS https://en.wikipedia.org/wiki/Server_Name_Indication
// On Apple platforms libetpan uses CFNetwork instead, that's why callback is not needed
r = mailpop3_socket_starttls_with_callback(mPop,
setMailStreamSSLContextServerName,
const_cast<void*>(static_cast<const void*>(MCUTF8(hostname()))));
#endif
if (r != MAILPOP3_NO_ERROR) {
* pError = ErrorStartTLSNotAvailable;
return;
Expand All @@ -237,7 +252,18 @@ void POPSession::connect(ErrorCode * pError)

case ConnectionTypeTLS:
MCLog("connect %s %u", MCUTF8(hostname()), (unsigned int) port());
#if __APPLE__
r = mailpop3_ssl_connect(mPop, MCUTF8(hostname()), port());
#else
// Passing callback to set the server name into SSL context
// Needed for SNI extension for TLS https://en.wikipedia.org/wiki/Server_Name_Indication
// On Apple platforms libetpan uses CFNetwork instead, that's why callback is not needed
r = mailpop3_ssl_connect_with_callback(mPop,
MCUTF8(hostname()),
port(),
setMailStreamSSLContextServerName,
const_cast<void*>(static_cast<const void*>(MCUTF8(hostname()))));
#endif
if (r != MAILPOP3_NO_ERROR) {
* pError = ErrorConnection;
return;
Expand Down
Loading
Loading