summary refs log tree commit diff stats
path: root/lib/pure/ssl_certs.nim
blob: dd09848beb3b2f0fcc08c977098c415a96c56cbb (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
#
#
#            Nim's Runtime Library
#        (c) Copyright 2017 Nim contributors
#
#    See the file "copying.txt", included in this
#    distribution, for details about the copyright.
#
## Scan for SSL/TLS CA certificates on disk
## The default locations can be overridden using the SSL_CERT_FILE and
## SSL_CERT_DIR environment variables.

import os, strutils

# FWIW look for files before scanning entire dirs.

when defined(macosx):
  const certificatePaths = [
    "/etc/ssl/cert.pem",
    "/System/Library/OpenSSL/certs/cert.pem"
  ]
elif defined(linux):
  const certificatePaths = [
    # Debian, Ubuntu, Arch: maintained by update-ca-certificates, SUSE, Gentoo
    # NetBSD (security/mozilla-rootcerts)
    # SLES10/SLES11, https://golang.org/issue/12139
    "/etc/ssl/certs/ca-certificates.crt",
    # OpenSUSE
    "/etc/ssl/ca-bundle.pem",
    # Red Hat 5+, Fedora, Centos
    "/etc/pki/tls/certs/ca-bundle.crt",
    # Red Hat 4
    "/usr/share/ssl/certs/ca-bundle.crt",
    # Fedora/RHEL
    "/etc/pki/tls/certs",
    # Android
    "/data/data/com.termux/files/usr/etc/tls/cert.pem",
    "/system/etc/security/cacerts",
  ]
elif defined(bsd):
  const certificatePaths = [
    # Debian, Ubuntu, Arch: maintained by update-ca-certificates, SUSE, Gentoo
    # NetBSD (security/mozilla-rootcerts)
    # SLES10/SLES11, https://golang.org/issue/12139
    "/etc/ssl/certs/ca-certificates.crt",
    # FreeBSD (security/ca-root-nss package)
    "/usr/local/share/certs/ca-root-nss.crt",
    # OpenBSD, FreeBSD (optional symlink)
    "/etc/ssl/cert.pem",
    # FreeBSD
    "/usr/local/share/certs",
    # NetBSD
    "/etc/openssl/certs",
  ]
else:
  const certificatePaths = [
    # Debian, Ubuntu, Arch: maintained by update-ca-certificates, SUSE, Gentoo
    # NetBSD (security/mozilla-rootcerts)
    # SLES10/SLES11, https://golang.org/issue/12139
    "/etc/ssl/certs/ca-certificates.crt",
    # OpenSUSE
    "/etc/ssl/ca-bundle.pem",
    # Red Hat 5+, Fedora, Centos
    "/etc/pki/tls/certs/ca-bundle.crt",
    # Red Hat 4
    "/usr/share/ssl/certs/ca-bundle.crt",
    # FreeBSD (security/ca-root-nss package)
    "/usr/local/share/certs/ca-root-nss.crt",
    # CentOS/RHEL 7
    "/etc/pki/ca-trust/extracted/pem/tls-ca-bundle.pem",
    # OpenBSD, FreeBSD (optional symlink)
    "/etc/ssl/cert.pem",
    # Fedora/RHEL
    "/etc/pki/tls/certs",
    # Android
    "/system/etc/security/cacerts",
    # FreeBSD
    "/usr/local/share/certs",
    # NetBSD
    "/etc/openssl/certs",
  ]

when defined(haiku):
  const
    B_FIND_PATH_EXISTING_ONLY = 0x4
    B_FIND_PATH_DATA_DIRECTORY = 6

  proc find_paths_etc(architecture: cstring, baseDirectory: cint,
                      subPath: cstring, flags: uint32,
                      paths: var ptr UncheckedArray[cstring],
                      pathCount: var csize_t): int32
                     {.importc, header: "<FindDirectory.h>".}
  proc free(p: pointer) {.importc, header: "<stdlib.h>".}

iterator scanSSLCertificates*(useEnvVars = false): string =
  ## Scan for SSL/TLS CA certificates on disk.
  ##
  ## if `useEnvVars` is true, the SSL_CERT_FILE and SSL_CERT_DIR
  ## environment variables can be used to override the certificate
  ## directories to scan or specify a CA certificate file.
  if useEnvVars and existsEnv("SSL_CERT_FILE"):
    yield getEnv("SSL_CERT_FILE")

  elif useEnvVars and existsEnv("SSL_CERT_DIR"):
    let p = getEnv("SSL_CERT_DIR")
    for fn in joinPath(p, "*").walkFiles():
      yield fn

  else:
    when defined(windows):
      const cacert = "cacert.pem"
      let pem = getAppDir() / cacert
      if fileExists(pem):
        yield pem
      else:
        let path = getEnv("PATH")
        for candidate in split(path, PathSep):
          if candidate.len != 0:
            let x = (if candidate[0] == '"' and candidate[^1] == '"':
                      substr(candidate, 1, candidate.len-2) else: candidate) / cacert
            if fileExists(x):
              yield x
    elif not defined(haiku):
      for p in certificatePaths:
        if p.endsWith(".pem") or p.endsWith(".crt"):
          if fileExists(p):
            yield p
        elif dirExists(p):
          # check if it's a dir where each cert is one file
          # named by it's hasg
          for fn in joinPath(p, "*.0").walkFiles:
            yield p.normalizePathEnd(true)
            break
          for fn in joinPath(p, "*").walkFiles():

            yield fn
    else:
      var
        paths: ptr UncheckedArray[cstring]
        size: csize_t
      let err = find_paths_etc(
        nil, B_FIND_PATH_DATA_DIRECTORY, "ssl/CARootCertificates.pem",
        B_FIND_PATH_EXISTING_ONLY, paths, size
      )
      if err == 0:
        defer: free(paths)
        for i in 0 ..< size:
          yield $paths[i]

# Certificates management on windows
# when defined(windows) or defined(nimdoc):
#
#   import 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.}