Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

net: add support for Windows certificate store #1438

Merged
merged 1 commit into from
Aug 30, 2024
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
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, CAstore)

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

Expand Down
Loading