summary refs log tree commit diff stats
path: root/tests/stdlib/thttpclient_ssl.nim
blob: 1c531eae94660302866672f745577991861f4e1c (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
discard """
  cmd: "nim $target --threads:on -d:ssl $options $file"
  disabled: "openbsd"
"""

#            Nim - Basic SSL integration tests
#        (c) Copyright 2018 Nim contributors
#
#    See the file "copying.txt", included in this
#    distribution, for details about the copyright.
#
## Warning: this test performs local networking.
## Test with:
## ./bin/nim c -d:ssl -p:. --threads:on -r tests/stdlib/thttpclient_ssl.nim

when not defined(windows):
  # Disabled on Windows due to old OpenSSL version

  import
    httpclient,
    net,
    openssl,
    os,
    strutils,
    threadpool,
    times,
    unittest

  # bogus self-signed certificate
  const
    certFile = "tests/stdlib/thttpclient_ssl_cert.pem"
    keyFile = "tests/stdlib/thttpclient_ssl_key.pem"

  proc log(msg: string) =
    when defined(ssldebug):
      echo "    [" & $epochTime() & "] " & msg
    # FIXME
    echo "    [" & $epochTime() & "] " & msg
    discard

  proc runServer(port: Port): bool {.thread.} =
    ## Run a trivial HTTPS server in a {.thread.}
    ## Exit after serving one request

    var socket = newSocket()
    socket.setSockOpt(OptReusePort, true)
    socket.bindAddr(port)

    var ctx = newContext(certFile=certFile, keyFile=keyFile)

    ##  Handle one connection
    socket.listen()

    var client: Socket
    var address = ""

    log "server: ready"
    socket.acceptAddr(client, address)
    log "server: incoming connection"

    var ssl: SslPtr = SSL_new(ctx.context)
    discard SSL_set_fd(ssl, client.getFd())
    log "server: accepting connection"
    ErrClearError()
    if SSL_accept(ssl) <= 0:
      ERR_print_errors_fp(stderr)
    else:
      const reply = "HTTP/1.0 200 OK\r\nServer: test\r\nContent-type: text/html\r\nContent-Length: 0\r\n\r\n"
      log "server: sending reply"
      discard SSL_write(ssl, reply.cstring, reply.len)

    log "server: receiving a line"
    let line = client.recvLine()
    log "server: received $# bytes" % $line.len
    log "closing"
    SSL_free(ssl)
    close(client)
    close(socket)
    log "server: exited"


  suite "SSL self signed certificate check":

    test "TCP socket":
      const port = 12347.Port
      let t = spawn runServer(port)
      sleep(100)
      var sock = newSocket()
      var ctx = newContext()
      ctx.wrapSocket(sock)
      try:
        log "client: connect"
        sock.connect("127.0.0.1", port)
        fail()
      except:
        let msg = getCurrentExceptionMsg()
        check(msg.contains("certificate verify failed"))

    test "HttpClient default: no check":
      const port = 12345.Port
      let t = spawn runServer(port)
      sleep(100)

      var client = newHttpClient(sslContext=newContext(verifyMode=CVerifyNone))
      try:
        log "client: connect"
        discard client.getContent("https://127.0.0.1:12345")
      except:
        let msg = getCurrentExceptionMsg()
        log "client: unexpected exception: " & msg
        fail()

    test "HttpClient with CVerifyPeer":
      const port = 12346.Port
      let t = spawn runServer(port)
      sleep(100)

      var client = newHttpClient(sslContext=newContext(verifyMode=CVerifyPeer))
      try:
        log "client: connect"
        discard client.getContent("https://127.0.0.1:12346")
        log "getContent should have raised an exception"
        fail()
      except:
        let msg = getCurrentExceptionMsg()
        log "client: exception: " & msg
        # SSL_shutdown:shutdown while in init
        if not (msg.contains("alert number 48") or
          msg.contains("certificate verify failed")):
          echo "CVerifyPeer exception: " & msg
          check(false)