Line data Source code
1 : /*
2 : * Copyright (c) 2019 Cisco and/or its affiliates.
3 : * Licensed under the Apache License, Version 2.0 (the "License");
4 : * you may not use this file except in compliance with the License.
5 : * You may obtain a copy of the License at:
6 : *
7 : * http://www.apache.org/licenses/LICENSE-2.0
8 : *
9 : * Unless required by applicable law or agreed to in writing, software
10 : * distributed under the License is distributed on an "AS IS" BASIS,
11 : * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 : * See the License for the specific language governing permissions and
13 : * limitations under the License.
14 : */
15 :
16 : #include <openssl/pem.h>
17 :
18 : #include <vppinfra/error.h>
19 :
20 : #include <quic/certs.h>
21 :
22 :
23 : int
24 276 : ptls_compare_separator_line (const char *line, const char *begin_or_end,
25 : const char *label)
26 : {
27 276 : int ret = strncmp (line, "-----", 5);
28 276 : size_t text_index = 5;
29 :
30 276 : if (ret == 0)
31 : {
32 24 : size_t begin_or_end_length = strlen (begin_or_end);
33 24 : ret = strncmp (line + text_index, begin_or_end, begin_or_end_length);
34 24 : text_index += begin_or_end_length;
35 : }
36 :
37 276 : if (ret == 0)
38 : {
39 24 : ret = line[text_index] - ' ';
40 24 : text_index++;
41 : }
42 :
43 276 : if (ret == 0)
44 : {
45 24 : size_t label_length = strlen (label);
46 24 : ret = strncmp (line + text_index, label, label_length);
47 24 : text_index += label_length;
48 : }
49 :
50 276 : if (ret == 0)
51 : {
52 24 : ret = strncmp (line + text_index, "-----", 5);
53 : }
54 :
55 276 : return ret;
56 : }
57 :
58 : int
59 24 : ptls_get_bio_pem_object (BIO * bio, const char *label, ptls_buffer_t * buf)
60 : {
61 24 : int ret = PTLS_ERROR_PEM_LABEL_NOT_FOUND;
62 : char line[256];
63 : ptls_base64_decode_state_t state;
64 :
65 : /* Get the label on a line by itself */
66 24 : while (BIO_gets (bio, line, 256))
67 : {
68 12 : if (ptls_compare_separator_line (line, "BEGIN", label) == 0)
69 : {
70 12 : ret = 0;
71 12 : ptls_base64_decode_init (&state);
72 12 : break;
73 : }
74 : }
75 : /* Get the data in the buffer */
76 276 : while (ret == 0 && BIO_gets (bio, line, 256))
77 : {
78 264 : if (ptls_compare_separator_line (line, "END", label) == 0)
79 : {
80 12 : if (state.status == PTLS_BASE64_DECODE_DONE
81 0 : || (state.status == PTLS_BASE64_DECODE_IN_PROGRESS
82 0 : && state.nbc == 0))
83 : {
84 12 : ret = 0;
85 : }
86 : else
87 : {
88 0 : ret = PTLS_ERROR_INCORRECT_BASE64;
89 : }
90 12 : break;
91 : }
92 : else
93 : {
94 252 : ret = ptls_base64_decode (line, &state, buf);
95 : }
96 : }
97 :
98 24 : return ret;
99 : }
100 :
101 : int
102 12 : ptls_load_bio_pem_objects (BIO * bio, const char *label, ptls_iovec_t * list,
103 : size_t list_max, size_t * nb_objects)
104 : {
105 12 : int ret = 0;
106 12 : size_t count = 0;
107 :
108 12 : *nb_objects = 0;
109 :
110 12 : if (ret == 0)
111 : {
112 24 : while (count < list_max)
113 : {
114 : ptls_buffer_t buf;
115 :
116 24 : ptls_buffer_init (&buf, "", 0);
117 :
118 24 : ret = ptls_get_bio_pem_object (bio, label, &buf);
119 :
120 24 : if (ret == 0)
121 : {
122 12 : if (buf.off > 0 && buf.is_allocated)
123 : {
124 12 : list[count].base = buf.base;
125 12 : list[count].len = buf.off;
126 12 : count++;
127 : }
128 : else
129 : {
130 0 : ptls_buffer_dispose (&buf);
131 : }
132 : }
133 : else
134 : {
135 12 : ptls_buffer_dispose (&buf);
136 12 : break;
137 : }
138 : }
139 : }
140 :
141 12 : if (ret == PTLS_ERROR_PEM_LABEL_NOT_FOUND && count > 0)
142 : {
143 12 : ret = 0;
144 : }
145 :
146 12 : *nb_objects = count;
147 :
148 12 : return ret;
149 : }
150 :
151 : #define PTLS_MAX_CERTS_IN_CONTEXT 16
152 :
153 : int
154 12 : ptls_load_bio_certificates (ptls_context_t * ctx, BIO * bio)
155 : {
156 12 : int ret = 0;
157 :
158 12 : ctx->certificates.list =
159 12 : (ptls_iovec_t *) malloc (PTLS_MAX_CERTS_IN_CONTEXT *
160 : sizeof (ptls_iovec_t));
161 :
162 12 : if (ctx->certificates.list == NULL)
163 : {
164 0 : ret = PTLS_ERROR_NO_MEMORY;
165 : }
166 : else
167 : {
168 : ret =
169 12 : ptls_load_bio_pem_objects (bio, "CERTIFICATE", ctx->certificates.list,
170 : PTLS_MAX_CERTS_IN_CONTEXT,
171 : &ctx->certificates.count);
172 : }
173 :
174 12 : return ret;
175 : }
176 :
177 : int
178 12 : load_bio_certificate_chain (ptls_context_t * ctx, const char *cert_data)
179 : {
180 : BIO *cert_bio;
181 12 : cert_bio = BIO_new_mem_buf (cert_data, -1);
182 12 : if (ptls_load_bio_certificates (ctx, cert_bio) != 0)
183 : {
184 0 : BIO_free (cert_bio);
185 0 : return -1;
186 : }
187 12 : BIO_free (cert_bio);
188 12 : return 0;
189 : }
190 :
191 : int
192 12 : load_bio_private_key (ptls_context_t * ctx, const char *pk_data)
193 : {
194 : static ptls_openssl_sign_certificate_t sc;
195 : EVP_PKEY *pkey;
196 : BIO *key_bio;
197 :
198 12 : key_bio = BIO_new_mem_buf (pk_data, -1);
199 12 : pkey = PEM_read_bio_PrivateKey (key_bio, NULL, NULL, NULL);
200 12 : BIO_free (key_bio);
201 :
202 12 : if (pkey == NULL)
203 0 : return -1;
204 :
205 12 : ptls_openssl_init_sign_certificate (&sc, pkey);
206 12 : EVP_PKEY_free (pkey);
207 :
208 12 : ctx->sign_certificate = &sc.super;
209 12 : return 0;
210 : }
|