tool_ssls.c (5981B)
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 "tool_setup.h" 25 26 #include "tool_cfgable.h" 27 #include "tool_cb_dbg.h" 28 #include "tool_msgs.h" 29 #include "tool_setopt.h" 30 #include "tool_ssls.h" 31 #include "tool_parsecfg.h" 32 33 /* The maximum line length for an ecoded session ticket */ 34 #define MAX_SSLS_LINE (64 * 1024) 35 36 37 static CURLcode tool_ssls_easy(struct OperationConfig *config, 38 CURLSH *share, CURL **peasy) 39 { 40 CURLcode result = CURLE_OK; 41 struct GlobalConfig *global = config->global; 42 43 *peasy = curl_easy_init(); 44 if(!*peasy) 45 return CURLE_OUT_OF_MEMORY; 46 47 result = curl_easy_setopt(*peasy, CURLOPT_SHARE, share); 48 if(!result && (global->tracetype != TRACE_NONE)) { 49 my_setopt(*peasy, CURLOPT_DEBUGFUNCTION, tool_debug_cb); 50 my_setopt(*peasy, CURLOPT_DEBUGDATA, config); 51 my_setopt_long(*peasy, CURLOPT_VERBOSE, 1L); 52 } 53 return result; 54 } 55 56 CURLcode tool_ssls_load(struct OperationConfig *config, 57 CURLSH *share, const char *filename) 58 { 59 FILE *fp; 60 CURL *easy = NULL; 61 struct dynbuf buf; 62 unsigned char *shmac = NULL, *sdata = NULL; 63 char *c, *line, *end; 64 size_t shmac_len, sdata_len; 65 CURLcode r = CURLE_OK; 66 int i, imported; 67 bool error = FALSE; 68 struct GlobalConfig *global = config->global; 69 70 curlx_dyn_init(&buf, MAX_SSLS_LINE); 71 fp = fopen(filename, FOPEN_READTEXT); 72 if(!fp) { /* ok if it does not exist */ 73 notef(global, "SSL session file does not exist (yet?): %s", filename); 74 goto out; 75 } 76 77 r = tool_ssls_easy(config, share, &easy); 78 if(r) 79 goto out; 80 81 i = imported = 0; 82 while(my_get_line(fp, &buf, &error)) { 83 ++i; 84 curl_free(shmac); 85 curl_free(sdata); 86 line = curlx_dyn_ptr(&buf); 87 88 c = memchr(line, ':', strlen(line)); 89 if(!c) { 90 warnf(global, "unrecognized line %d in ssl session file %s", 91 i, filename); 92 continue; 93 } 94 *c = '\0'; 95 r = curlx_base64_decode(line, &shmac, &shmac_len); 96 if(r) { 97 warnf(global, "invalid shmax base64 encoding in line %d", i); 98 continue; 99 } 100 line = c + 1; 101 end = line + strlen(line) - 1; 102 while((end > line) && (*end == '\n' || *end == '\r' || ISBLANK(*line))) { 103 *end = '\0'; 104 --end; 105 } 106 r = curlx_base64_decode(line, &sdata, &sdata_len); 107 if(r) { 108 warnf(global, "invalid sdata base64 encoding in line %d: %s", i, line); 109 continue; 110 } 111 112 r = curl_easy_ssls_import(easy, NULL, shmac, shmac_len, sdata, sdata_len); 113 if(r) { 114 warnf(global, "import of session from line %d rejected(%d)", i, r); 115 continue; 116 } 117 ++imported; 118 } 119 if(error) 120 r = CURLE_FAILED_INIT; 121 else 122 r = CURLE_OK; 123 124 out: 125 if(easy) 126 curl_easy_cleanup(easy); 127 if(fp) 128 fclose(fp); 129 curlx_dyn_free(&buf); 130 curl_free(shmac); 131 curl_free(sdata); 132 return r; 133 } 134 135 struct tool_ssls_ctx { 136 struct GlobalConfig *global; 137 FILE *fp; 138 int exported; 139 }; 140 141 static CURLcode tool_ssls_exp(CURL *easy, void *userptr, 142 const char *session_key, 143 const unsigned char *shmac, size_t shmac_len, 144 const unsigned char *sdata, size_t sdata_len, 145 curl_off_t valid_until, int ietf_tls_id, 146 const char *alpn, size_t earlydata_max) 147 { 148 struct tool_ssls_ctx *ctx = userptr; 149 char *enc = NULL; 150 size_t enc_len; 151 CURLcode r; 152 153 (void)easy; 154 (void)valid_until; 155 (void)ietf_tls_id; 156 (void)alpn; 157 (void)earlydata_max; 158 if(!ctx->exported) 159 fputs("# Your SSL session cache. https://curl.se/docs/ssl-sessions.html\n" 160 "# This file was generated by libcurl! Edit at your own risk.\n", 161 ctx->fp); 162 163 r = curlx_base64_encode((const char *)shmac, shmac_len, &enc, &enc_len); 164 if(r) 165 goto out; 166 r = CURLE_WRITE_ERROR; 167 if(enc_len != fwrite(enc, 1, enc_len, ctx->fp)) 168 goto out; 169 if(EOF == fputc(':', ctx->fp)) 170 goto out; 171 curl_free(enc); 172 r = curlx_base64_encode((const char *)sdata, sdata_len, &enc, &enc_len); 173 if(r) 174 goto out; 175 r = CURLE_WRITE_ERROR; 176 if(enc_len != fwrite(enc, 1, enc_len, ctx->fp)) 177 goto out; 178 if(EOF == fputc('\n', ctx->fp)) 179 goto out; 180 r = CURLE_OK; 181 ctx->exported++; 182 out: 183 if(r) 184 warnf(ctx->global, "Warning: error saving SSL session for '%s': %d", 185 session_key, r); 186 curl_free(enc); 187 return r; 188 } 189 190 CURLcode tool_ssls_save(struct OperationConfig *config, 191 CURLSH *share, const char *filename) 192 { 193 struct tool_ssls_ctx ctx; 194 CURL *easy = NULL; 195 CURLcode r = CURLE_OK; 196 197 ctx.global = config->global; 198 ctx.exported = 0; 199 ctx.fp = fopen(filename, FOPEN_WRITETEXT); 200 if(!ctx.fp) { 201 warnf(config->global, "Warning: Failed to create SSL session file %s", 202 filename); 203 goto out; 204 } 205 206 r = tool_ssls_easy(config, share, &easy); 207 if(r) 208 goto out; 209 210 r = curl_easy_ssls_export(easy, tool_ssls_exp, &ctx); 211 212 out: 213 if(easy) 214 curl_easy_cleanup(easy); 215 if(ctx.fp) 216 fclose(ctx.fp); 217 return r; 218 }