Coverage Report

Created: 2022-10-16 06:45

/src/curl/lib/vtls/keylog.c
Line
Count
Source (jump to first uncovered line)
1
/***************************************************************************
2
 *                                  _   _ ____  _
3
 *  Project                     ___| | | |  _ \| |
4
 *                             / __| | | | |_) | |
5
 *                            | (__| |_| |  _ <| |___
6
 *                             \___|\___/|_| \_\_____|
7
 *
8
 * Copyright (C) 1998 - 2022, Daniel Stenberg, <daniel@haxx.se>, et al.
9
 *
10
 * This software is licensed as described in the file COPYING, which
11
 * you should have received as part of this distribution. The terms
12
 * are also available at https://curl.se/docs/copyright.html.
13
 *
14
 * You may opt to use, copy, modify, merge, publish, distribute and/or sell
15
 * copies of the Software, and permit persons to whom the Software is
16
 * furnished to do so, under the terms of the COPYING file.
17
 *
18
 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19
 * KIND, either express or implied.
20
 *
21
 * SPDX-License-Identifier: curl
22
 *
23
 ***************************************************************************/
24
#include "curl_setup.h"
25
26
#include "keylog.h"
27
#include <curl/curl.h>
28
29
/* The last #include files should be: */
30
#include "curl_memory.h"
31
#include "memdebug.h"
32
33
0
#define KEYLOG_LABEL_MAXLEN (sizeof("CLIENT_HANDSHAKE_TRAFFIC_SECRET") - 1)
34
35
0
#define CLIENT_RANDOM_SIZE  32
36
37
/*
38
 * The master secret in TLS 1.2 and before is always 48 bytes. In TLS 1.3, the
39
 * secret size depends on the cipher suite's hash function which is 32 bytes
40
 * for SHA-256 and 48 bytes for SHA-384.
41
 */
42
0
#define SECRET_MAXLEN       48
43
44
45
/* The fp for the open SSLKEYLOGFILE, or NULL if not open */
46
static FILE *keylog_file_fp;
47
48
void
49
Curl_tls_keylog_open(void)
50
19
{
51
19
  char *keylog_file_name;
52
53
19
  if(!keylog_file_fp) {
54
19
    keylog_file_name = curl_getenv("SSLKEYLOGFILE");
55
19
    if(keylog_file_name) {
56
0
      keylog_file_fp = fopen(keylog_file_name, FOPEN_APPENDTEXT);
57
0
      if(keylog_file_fp) {
58
#ifdef WIN32
59
        if(setvbuf(keylog_file_fp, NULL, _IONBF, 0))
60
#else
61
0
        if(setvbuf(keylog_file_fp, NULL, _IOLBF, 4096))
62
0
#endif
63
0
        {
64
0
          fclose(keylog_file_fp);
65
0
          keylog_file_fp = NULL;
66
0
        }
67
0
      }
68
0
      Curl_safefree(keylog_file_name);
69
0
    }
70
19
  }
71
19
}
72
73
void
74
Curl_tls_keylog_close(void)
75
0
{
76
0
  if(keylog_file_fp) {
77
0
    fclose(keylog_file_fp);
78
0
    keylog_file_fp = NULL;
79
0
  }
80
0
}
81
82
bool
83
Curl_tls_keylog_enabled(void)
84
0
{
85
0
  return keylog_file_fp != NULL;
86
0
}
87
88
bool
89
Curl_tls_keylog_write_line(const char *line)
90
0
{
91
  /* The current maximum valid keylog line length LF and NUL is 195. */
92
0
  size_t linelen;
93
0
  char buf[256];
94
95
0
  if(!keylog_file_fp || !line) {
96
0
    return false;
97
0
  }
98
99
0
  linelen = strlen(line);
100
0
  if(linelen == 0 || linelen > sizeof(buf) - 2) {
101
    /* Empty line or too big to fit in a LF and NUL. */
102
0
    return false;
103
0
  }
104
105
0
  memcpy(buf, line, linelen);
106
0
  if(line[linelen - 1] != '\n') {
107
0
    buf[linelen++] = '\n';
108
0
  }
109
0
  buf[linelen] = '\0';
110
111
  /* Using fputs here instead of fprintf since libcurl's fprintf replacement
112
     may not be thread-safe. */
113
0
  fputs(buf, keylog_file_fp);
114
0
  return true;
115
0
}
116
117
bool
118
Curl_tls_keylog_write(const char *label,
119
                      const unsigned char client_random[CLIENT_RANDOM_SIZE],
120
                      const unsigned char *secret, size_t secretlen)
121
0
{
122
0
  const char *hex = "0123456789ABCDEF";
123
0
  size_t pos, i;
124
0
  char line[KEYLOG_LABEL_MAXLEN + 1 + 2 * CLIENT_RANDOM_SIZE + 1 +
125
0
            2 * SECRET_MAXLEN + 1 + 1];
126
127
0
  if(!keylog_file_fp) {
128
0
    return false;
129
0
  }
130
131
0
  pos = strlen(label);
132
0
  if(pos > KEYLOG_LABEL_MAXLEN || !secretlen || secretlen > SECRET_MAXLEN) {
133
    /* Should never happen - sanity check anyway. */
134
0
    return false;
135
0
  }
136
137
0
  memcpy(line, label, pos);
138
0
  line[pos++] = ' ';
139
140
  /* Client Random */
141
0
  for(i = 0; i < CLIENT_RANDOM_SIZE; i++) {
142
0
    line[pos++] = hex[client_random[i] >> 4];
143
0
    line[pos++] = hex[client_random[i] & 0xF];
144
0
  }
145
0
  line[pos++] = ' ';
146
147
  /* Secret */
148
0
  for(i = 0; i < secretlen; i++) {
149
0
    line[pos++] = hex[secret[i] >> 4];
150
0
    line[pos++] = hex[secret[i] & 0xF];
151
0
  }
152
0
  line[pos++] = '\n';
153
0
  line[pos] = '\0';
154
155
  /* Using fputs here instead of fprintf since libcurl's fprintf replacement
156
     may not be thread-safe. */
157
0
  fputs(line, keylog_file_fp);
158
0
  return true;
159
0
}