summary refs log tree commit diff stats
path: root/lib/pure/ssl_certs.nim
blob: 9845de9b6a42c788b925d3f0bdced9d41c9b7564 (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
#
#
#            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
from ospaths import existsEnv, getEnv
import strutils

# SECURITY: this unnecessarily scans through dirs/files regardless of the
# actual host OS/distribution. Hopefully all the paths are writeble only by
# root.

# FWIW look for files before scanning entire dirs.

const certificate_paths = [
    # 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",
    # Mac OS X
    "/System/Library/OpenSSL/certs/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): 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 existsEnv("SSL_CERT_FILE"):
    yield getEnv("SSL_CERT_FILE")

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

  else:
    when not defined(haiku):
      for p in certificate_paths:
        if p.endsWith(".pem") or p.endsWith(".crt"):
          if existsFile(p):
            yield p
        elif existsDir(p):
          for fn in joinPath(p, "*").walkFiles():
            yield fn
    else:
      var
        paths: ptr UncheckedArray[cstring]
        size: csize
      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.}
56669c'>^
5e15dec17 ^
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

 
                            
                                         







                                                   
                                                                        




                                   
                                                           


                                                                         



                                                  
                                                                            



                                
                                                      




                                          
           
                                          
                                              


                                 
                                     
                                                                              
         
                                           
                                              
                                         
       
                                        
                                            


                                                    


                                                                       






                                                                   
 
                                      


                                                                         
                                                   
                       






                                                              
                                                          







                                                 
 
                         
                  



                                               
                                               


                                                         


                                                                

                                                      
 
                          
#
#
#           The Nim Compiler
#        (c) Copyright 2013 Andreas Rumpf
#
#    See the file "copying.txt", included in this
#    distribution, for details about the copyright.
#

## Template evaluation engine. Now hygienic.

import
  strutils, options, ast, astalgo, msgs, os, idents, wordrecg, renderer,
  rodread

type
  TemplCtx {.pure, final.} = object
    owner, genSymOwner: PSym
    instLines: bool   # use the instantiation lines numbers
    mapping: TIdTable # every gensym'ed symbol needs to be mapped to some
                      # new symbol

proc copyNode(ctx: TemplCtx, a, b: PNode): PNode =
  result = copyNode(a)
  if ctx.instLines: result.info = b.info

proc evalTemplateAux(templ, actual: PNode, c: var TemplCtx, result: PNode) =
  case templ.kind
  of nkSym:
    var s = templ.sym
    if s.owner.id == c.owner.id:
      if s.kind == skParam and sfGenSym notin s.flags:
        let x = actual.sons[s.position]
        if x.kind == nkArgList:
          for y in items(x): result.add(y)
        else:
          result.add copyTree(x)
      else:
        internalAssert sfGenSym in s.flags
        var x = PSym(idTableGet(c.mapping, s))
        if x == nil:
          x = copySym(s, false)
          x.owner = c.genSymOwner
          idTablePut(c.mapping, s, x)
        result.add newSymNode(x, if c.instLines: actual.info else: templ.info)
    else:
      result.add copyNode(c, templ, actual)
  of nkNone..nkIdent, nkType..nkNilLit: # atom
    result.add copyNode(c, templ, actual)
  else:
    var res = copyNode(c, templ, actual)
    for i in countup(0, sonsLen(templ) - 1):
      evalTemplateAux(templ.sons[i], actual, c, res)
    result.add res

proc evalTemplateArgs(n: PNode, s: PSym): PNode =
  # if the template has zero arguments, it can be called without ``()``
  # `n` is then a nkSym or something similar
  var a: int
  case n.kind
  of nkCall, nkInfix, nkPrefix, nkPostfix, nkCommand, nkCallStrLit:
    a = sonsLen(n)
  else: a = 0
  var f = s.typ.sonsLen
  if a > f: globalError(n.info, errWrongNumberOfArguments)

  result = newNodeI(nkArgList, n.info)
  for i in countup(1, f - 1):
    var arg = if i < a: n.sons[i] else: copyTree(s.typ.n.sons[i].sym.ast)
    if arg == nil or arg.kind == nkEmpty:
      localError(n.info, errWrongNumberOfArguments)
    addSon(result, arg)

var evalTemplateCounter* = 0
  # to prevent endless recursion in templates instantiation

proc evalTemplate*(n: PNode, tmpl, genSymOwner: PSym): PNode =
  inc(evalTemplateCounter)
  if evalTemplateCounter > 100:
    globalError(n.info, errTemplateInstantiationTooNested)
    result = n

  # replace each param by the corresponding node:
  var args = evalTemplateArgs(n, tmpl)
  var ctx: TemplCtx
  ctx.owner = tmpl
  ctx.genSymOwner = genSymOwner
  initIdTable(ctx.mapping)

  let body = tmpl.getBody
  if isAtom(body):
    result = newNodeI(nkPar, body.info)
    evalTemplateAux(body, args, ctx, result)
    if result.len == 1: result = result.sons[0]
    else:
      localError(result.info, errIllFormedAstX,
                  renderTree(result, {renderNoComments}))
  else:
    result = copyNode(body)
    ctx.instLines = body.kind notin {nkStmtList, nkStmtListExpr,
                                     nkBlockStmt, nkBlockExpr}
    if ctx.instLines: result.info = n.info
    for i in countup(0, safeLen(body) - 1):
      evalTemplateAux(body.sons[i], args, ctx, result)

  dec(evalTemplateCounter)