keylog.c (4011B)
1 /*************************************************************************** 2 * _ _ ____ _ 3 * Project ___| | | | _ \| | 4 * / __| | | | |_) | | 5 * | (__| |_| | _ <| |___ 6 * \___|\___/|_| \_\_____| 7 * 8 * Copyright (C) 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 #if defined(USE_OPENSSL) || \ 27 defined(USE_GNUTLS) || \ 28 defined(USE_WOLFSSL) || \ 29 (defined(USE_NGTCP2) && defined(USE_NGHTTP3)) || \ 30 defined(USE_QUICHE) || \ 31 defined(USE_RUSTLS) 32 33 #include "keylog.h" 34 #include <curl/curl.h> 35 #include "../escape.h" 36 37 /* The last #include files should be: */ 38 #include "../curl_memory.h" 39 #include "../memdebug.h" 40 41 /* The fp for the open SSLKEYLOGFILE, or NULL if not open */ 42 static FILE *keylog_file_fp; 43 44 void 45 Curl_tls_keylog_open(void) 46 { 47 char *keylog_file_name; 48 49 if(!keylog_file_fp) { 50 keylog_file_name = curl_getenv("SSLKEYLOGFILE"); 51 if(keylog_file_name) { 52 keylog_file_fp = fopen(keylog_file_name, FOPEN_APPENDTEXT); 53 if(keylog_file_fp) { 54 #ifdef _WIN32 55 if(setvbuf(keylog_file_fp, NULL, _IONBF, 0)) 56 #else 57 if(setvbuf(keylog_file_fp, NULL, _IOLBF, 4096)) 58 #endif 59 { 60 fclose(keylog_file_fp); 61 keylog_file_fp = NULL; 62 } 63 } 64 Curl_safefree(keylog_file_name); 65 } 66 } 67 } 68 69 void 70 Curl_tls_keylog_close(void) 71 { 72 if(keylog_file_fp) { 73 fclose(keylog_file_fp); 74 keylog_file_fp = NULL; 75 } 76 } 77 78 bool 79 Curl_tls_keylog_enabled(void) 80 { 81 return keylog_file_fp != NULL; 82 } 83 84 bool 85 Curl_tls_keylog_write_line(const char *line) 86 { 87 /* The current maximum valid keylog line length LF and NUL is 195. */ 88 size_t linelen; 89 char buf[256]; 90 91 if(!keylog_file_fp || !line) { 92 return FALSE; 93 } 94 95 linelen = strlen(line); 96 if(linelen == 0 || linelen > sizeof(buf) - 2) { 97 /* Empty line or too big to fit in an LF and NUL. */ 98 return FALSE; 99 } 100 101 memcpy(buf, line, linelen); 102 if(line[linelen - 1] != '\n') { 103 buf[linelen++] = '\n'; 104 } 105 buf[linelen] = '\0'; 106 107 /* Using fputs here instead of fprintf since libcurl's fprintf replacement 108 may not be thread-safe. */ 109 fputs(buf, keylog_file_fp); 110 return TRUE; 111 } 112 113 bool 114 Curl_tls_keylog_write(const char *label, 115 const unsigned char client_random[CLIENT_RANDOM_SIZE], 116 const unsigned char *secret, size_t secretlen) 117 { 118 size_t pos, i; 119 unsigned char line[KEYLOG_LABEL_MAXLEN + 1 + 2 * CLIENT_RANDOM_SIZE + 1 + 120 2 * SECRET_MAXLEN + 1 + 1]; 121 122 if(!keylog_file_fp) { 123 return FALSE; 124 } 125 126 pos = strlen(label); 127 if(pos > KEYLOG_LABEL_MAXLEN || !secretlen || secretlen > SECRET_MAXLEN) { 128 /* Should never happen - sanity check anyway. */ 129 return FALSE; 130 } 131 132 memcpy(line, label, pos); 133 line[pos++] = ' '; 134 135 /* Client Random */ 136 for(i = 0; i < CLIENT_RANDOM_SIZE; i++) { 137 Curl_hexbyte(&line[pos], client_random[i]); 138 pos += 2; 139 } 140 line[pos++] = ' '; 141 142 /* Secret */ 143 for(i = 0; i < secretlen; i++) { 144 Curl_hexbyte(&line[pos], secret[i]); 145 pos += 2; 146 } 147 line[pos++] = '\n'; 148 line[pos] = '\0'; 149 150 /* Using fputs here instead of fprintf since libcurl's fprintf replacement 151 may not be thread-safe. */ 152 fputs((char *)line, keylog_file_fp); 153 return TRUE; 154 } 155 156 #endif /* TLS or QUIC backend */