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