Skip to content

Commit

Permalink
net: add support for Windows certificate store
Browse files Browse the repository at this point in the history
  • Loading branch information
alaviss committed Aug 29, 2024
1 parent 4d290f4 commit 4130a6e
Show file tree
Hide file tree
Showing 4 changed files with 29 additions and 36 deletions.
7 changes: 0 additions & 7 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -140,13 +140,6 @@ jobs:
if: runner.os == 'Windows'
run: vcpkg install pcre sqlite3

- name: Download CA certificates (Windows)
if: runner.os == 'Windows'
run: |
$binPath = Join-Path $PWD "vcpkg" "installed" "x64-mingw-dynamic-release" "bin"
Invoke-WebRequest https://curl.se/ca/cacert.pem -OutFile (Join-Path $binPath "cacert.pem")
shell: pwsh

- name: Set Xcode version (macOS M1)
if: runner.os == 'macOS' && runner.arch == 'ARM64'
uses: maxim-lobanov/setup-xcode@v1
Expand Down
25 changes: 20 additions & 5 deletions lib/pure/net.nim
Original file line number Diff line number Diff line change
Expand Up @@ -29,11 +29,15 @@
## ==============
##
## On Windows the SSL library checks for valid certificates.
## It uses the `cacert.pem` file for this purpose which was extracted
## from `https://curl.se/ca/cacert.pem`. Besides
## the OpenSSL DLLs (e.g. libssl-1_1-x64.dll, libcrypto-1_1-x64.dll) you
## also need to ship `cacert.pem` with your `.exe` file.
##
## It uses a Certificate Authority (CA) bundle and/or the Windows Root
## Certificate store (only with OpenSSL >= 3.2.0) for this purpose.
##
## The CA bundle should be named `cacert.pem` and placed next to the
## program `.exe` or in `PATH` and can be obtained from
## `https://curl.se/ca/cacert.pem`. This bundle will be loaded
## regardless of whether the Windows Certificate Root store is used,
## but is only required when the Root Certificate store can not be used.
##
## Examples
## ========
Expand Down Expand Up @@ -668,7 +672,18 @@ when defineSsl:
else:
# Scan for certs in known locations. For CVerifyPeerUseEnvVars also scan
# the SSL_CERT_FILE and SSL_CERT_DIR env vars
var found = false
var found =
when not defined(windows) or defined(openssl111):
false
else:
# Try loading the root certificate store on Windows.
#
# Note that we will still load cacert.pem after this, just that
# it won't be considered an error if we couldn't. This is because
# OpenSSL won't raise an error here if the store doesn't exist.
OpenSSL_version_num() >= 0x30200000 and
newCTX.SSL_CTX_load_verify_store("org.openssl.winstore:") == VerifySuccess

let useEnvVars = (if verifyMode == CVerifyPeerUseEnvVars: true else: false)
for fn in scanSSLCertificates(useEnvVars = useEnvVars):
if newCTX.SSL_CTX_load_verify_locations(fn, nil) == VerifySuccess:
Expand Down
24 changes: 0 additions & 24 deletions lib/pure/ssl_certs.nim
Original file line number Diff line number Diff line change
Expand Up @@ -140,27 +140,3 @@ iterator scanSSLCertificates*(useEnvVars = false): string =
defer: free(paths)
for i in 0 ..< size:
yield $paths[i]

# Certificates management on windows
# when defined(windows) or defined(nimdoc):
#
# import std/openssl
#
# type
# PCCertContext {.final, pure.} = pointer
# X509 {.final, pure.} = pointer
# CertStore {.final, pure.} = pointer
#
# # OpenSSL cert store
#
# {.push stdcall, dynlib: "kernel32", importc.}
#
# proc CertOpenSystemStore*(hprov: pointer=nil, szSubsystemProtocol: cstring): CertStore
#
# proc CertEnumCertificatesInStore*(hCertStore: CertStore, pPrevCertContext: PCCertContext): pointer
#
# proc CertFreeCertificateContext*(pContext: PCCertContext): bool
#
# proc CertCloseStore*(hCertStore:CertStore, flags:cint): bool
#
# {.pop.}
9 changes: 9 additions & 0 deletions lib/wrappers/openssl.nim
Original file line number Diff line number Diff line change
Expand Up @@ -245,6 +245,8 @@ const
when compileOption("dynlibOverride", "ssl") or defined(noOpenSSLHacks):
when not defined(openssl111):
proc SSL_get_peer_certificate*(ssl: SslCtx): PX509 {.cdecl, dynlib: DLLSSLName, importc: "SSL_get1_peer_certificate".}

proc SSL_CTX_load_verify_store*(ssl: SslCtx, CAstore: cstring): cint {.cdecl, dynlib: DLLSSLName, importc.}
else:
proc SSL_get_peer_certificate*(ssl: SslCtx): PX509 {.cdecl, dynlib: DLLSSLName, importc: "SSL_get_peer_certificate".}
else:
Expand Down Expand Up @@ -290,6 +292,13 @@ else:
)
if not thisProc.isNil: result = thisProc(ssl)

proc SSL_CTX_load_verify_store*(ssl: SslCtx, CAstore: cstring): cint {.gcsafe, tags: [].} =
{.cast(tags: []), cast(gcsafe).}:
var thisProc {.global.}: proc (ssl: SslCtx, CAstore: cstring): cint {.cdecl.}
if thisProc.isNil:
thisProc = cast[typeof(thisProc)](sslSymThrows("SSL_CTX_load_verify_store"))
result = thisProc(ssl)

proc TLS_method*(): PSSL_METHOD {.cdecl, dynlib: DLLSSLName, importc.}
proc OpenSSL_version_num*(): culong {.cdecl, dynlib: DLLUtilName, importc.}

Expand Down

0 comments on commit 4130a6e

Please sign in to comment.