updated Doxyfile
[strongswan.git] / src / charon / encoding / payloads / cert_payload.c
1 /*
2 * Copyright (C) 2008 Tobias Brunner
3 * Copyright (C) 2005-2007 Martin Willi
4 * Copyright (C) 2005 Jan Hutter
5 * Hochschule fuer Technik Rapperswil
6 *
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the
9 * Free Software Foundation; either version 2 of the License, or (at your
10 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
11 *
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
14 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
15 * for more details.
16 *
17 * $Id$
18 */
19
20 #include <stddef.h>
21 #include <ctype.h>
22
23 #include <daemon.h>
24
25 #include "cert_payload.h"
26
27 ENUM(cert_encoding_names, ENC_PKCS7_WRAPPED_X509, ENC_OCSP_CONTENT,
28 "ENC_PKCS7_WRAPPED_X509",
29 "ENC_PGP",
30 "ENC_DNS_SIGNED_KEY",
31 "ENC_X509_SIGNATURE",
32 "ENC_X509_KEY_EXCHANGE",
33 "ENC_KERBEROS_TOKENS",
34 "ENC_CRL",
35 "ENC_ARL",
36 "ENC_SPKI",
37 "ENC_X509_ATTRIBUTE",
38 "ENC_RAW_RSA_KEY",
39 "ENC_X509_HASH_AND_URL",
40 "ENC_X509_HASH_AND_URL_BUNDLE",
41 "ENC_OCSP_CONTENT",
42 );
43
44 typedef struct private_cert_payload_t private_cert_payload_t;
45
46 /**
47 * Private data of an cert_payload_t object.
48 *
49 */
50 struct private_cert_payload_t {
51 /**
52 * Public cert_payload_t interface.
53 */
54 cert_payload_t public;
55
56 /**
57 * Next payload type.
58 */
59 u_int8_t next_payload;
60
61 /**
62 * Critical flag.
63 */
64 bool critical;
65
66 /**
67 * Length of this payload.
68 */
69 u_int16_t payload_length;
70
71 /**
72 * Encoding of the CERT Data.
73 */
74 u_int8_t encoding;
75
76 /**
77 * The contained cert data value.
78 */
79 chunk_t data;
80
81 /**
82 * TRUE if the "Hash and URL" data is invalid
83 */
84 bool invalid_hash_and_url;
85 };
86
87 /**
88 * Encoding rules to parse or generate a CERT payload
89 *
90 * The defined offsets are the positions in a object of type
91 * private_cert_payload_t.
92 *
93 */
94 encoding_rule_t cert_payload_encodings[] = {
95 /* 1 Byte next payload type, stored in the field next_payload */
96 { U_INT_8, offsetof(private_cert_payload_t, next_payload) },
97 /* the critical bit */
98 { FLAG, offsetof(private_cert_payload_t, critical) },
99 /* 7 Bit reserved bits, nowhere stored */
100 { RESERVED_BIT, 0 },
101 { RESERVED_BIT, 0 },
102 { RESERVED_BIT, 0 },
103 { RESERVED_BIT, 0 },
104 { RESERVED_BIT, 0 },
105 { RESERVED_BIT, 0 },
106 { RESERVED_BIT, 0 },
107 /* Length of the whole payload*/
108 { PAYLOAD_LENGTH, offsetof(private_cert_payload_t, payload_length)},
109 /* 1 Byte CERT type*/
110 { U_INT_8, offsetof(private_cert_payload_t, encoding) },
111 /* some cert data bytes, length is defined in PAYLOAD_LENGTH */
112 { CERT_DATA, offsetof(private_cert_payload_t, data) }
113 };
114
115 /*
116 1 2 3
117 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
118 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
119 ! Next Payload !C! RESERVED ! Payload Length !
120 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
121 ! Cert Encoding ! !
122 +-+-+-+-+-+-+-+-+ !
123 ~ Certificate Data ~
124 ! !
125 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
126 */
127
128 /**
129 * Implementation of payload_t.verify.
130 */
131 static status_t verify(private_cert_payload_t *this)
132 {
133 if (this->encoding == ENC_X509_HASH_AND_URL ||
134 this->encoding == ENC_X509_HASH_AND_URL_BUNDLE)
135 {
136 /* coarse verification of "Hash and URL" encoded certificates */
137 if (this->data.len <= 20)
138 {
139 DBG1(DBG_ENC, "invalid payload length for hash-and-url (%d), ignore",
140 this->data.len);
141 this->invalid_hash_and_url = TRUE;
142 return SUCCESS;
143 }
144
145 int i = 20; /* skipping the hash */
146 for (; i < this->data.len; ++i)
147 {
148 if (this->data.ptr[i] == '\0')
149 {
150 /* null terminated, fine */
151 return SUCCESS;
152 }
153 else if (!isprint(this->data.ptr[i]))
154 {
155 DBG1(DBG_ENC, "non printable characters in url of hash-and-url"
156 " encoded certificate payload, ignore");
157 this->invalid_hash_and_url = TRUE;
158 return SUCCESS;
159 }
160 }
161
162 /* URL is not null terminated, correct that */
163 chunk_t data = chunk_alloc(this->data.len + 1);
164 memcpy(data.ptr, this->data.ptr, this->data.len);
165 data.ptr[this->data.len] = '\0';
166 chunk_free(&this->data);
167 this->data = data;
168 }
169 return SUCCESS;
170 }
171
172 /**
173 * Implementation of cert_payload_t.get_encoding_rules.
174 */
175 static void get_encoding_rules(private_cert_payload_t *this,
176 encoding_rule_t **rules, size_t *rule_count)
177 {
178 *rules = cert_payload_encodings;
179 *rule_count = sizeof(cert_payload_encodings) / sizeof(encoding_rule_t);
180 }
181
182 /**
183 * Implementation of payload_t.get_type.
184 */
185 static payload_type_t get_payload_type(private_cert_payload_t *this)
186 {
187 return CERTIFICATE;
188 }
189
190 /**
191 * Implementation of payload_t.get_next_type.
192 */
193 static payload_type_t get_next_type(private_cert_payload_t *this)
194 {
195 return this->next_payload;
196 }
197
198 /**
199 * Implementation of payload_t.set_next_type.
200 */
201 static void set_next_type(private_cert_payload_t *this,payload_type_t type)
202 {
203 this->next_payload = type;
204 }
205
206 /**
207 * Implementation of payload_t.get_length.
208 */
209 static size_t get_length(private_cert_payload_t *this)
210 {
211 return this->payload_length;
212 }
213
214 /**
215 * Implementation of cert_payload_t.get_cert_encoding.
216 */
217 static cert_encoding_t get_cert_encoding(private_cert_payload_t *this)
218 {
219 return this->encoding;
220 }
221
222 /**
223 * Implementation of cert_payload_t.get_cert.
224 */
225 static certificate_t *get_cert(private_cert_payload_t *this)
226 {
227 if (this->encoding != ENC_X509_SIGNATURE)
228 {
229 return NULL;
230 }
231 return lib->creds->create(lib->creds, CRED_CERTIFICATE, CERT_X509,
232 BUILD_BLOB_ASN1_DER, this->data,
233 BUILD_END);
234 }
235
236 /**
237 * Implementation of cert_payload_t.get_hash.
238 */
239 static chunk_t get_hash(private_cert_payload_t *this)
240 {
241 chunk_t hash = chunk_empty;
242 if ((this->encoding != ENC_X509_HASH_AND_URL &&
243 this->encoding != ENC_X509_HASH_AND_URL_BUNDLE) ||
244 this->invalid_hash_and_url)
245 {
246 return hash;
247 }
248 hash.ptr = this->data.ptr;
249 hash.len = 20;
250 return hash;
251 }
252
253 /**
254 * Implementation of cert_payload_t.get_url.
255 */
256 static char *get_url(private_cert_payload_t *this)
257 {
258 if ((this->encoding != ENC_X509_HASH_AND_URL &&
259 this->encoding != ENC_X509_HASH_AND_URL_BUNDLE) ||
260 this->invalid_hash_and_url)
261 {
262 return NULL;
263 }
264 return (char*)this->data.ptr + 20;
265 }
266
267 /**
268 * Implementation of payload_t.destroy and cert_payload_t.destroy.
269 */
270 static void destroy(private_cert_payload_t *this)
271 {
272 chunk_free(&this->data);
273 free(this);
274 }
275
276 /*
277 * Described in header
278 */
279 cert_payload_t *cert_payload_create()
280 {
281 private_cert_payload_t *this = malloc_thing(private_cert_payload_t);
282
283 this->public.payload_interface.verify = (status_t (*) (payload_t*))verify;
284 this->public.payload_interface.get_encoding_rules = (void (*) (payload_t*,encoding_rule_t**, size_t*))get_encoding_rules;
285 this->public.payload_interface.get_length = (size_t (*) (payload_t*))get_length;
286 this->public.payload_interface.get_next_type = (payload_type_t (*) (payload_t*))get_next_type;
287 this->public.payload_interface.set_next_type = (void (*) (payload_t*,payload_type_t))set_next_type;
288 this->public.payload_interface.get_type = (payload_type_t (*) (payload_t*))get_payload_type;
289 this->public.payload_interface.destroy = (void (*) (payload_t*))destroy;
290
291 this->public.destroy = (void (*) (cert_payload_t*))destroy;
292 this->public.get_cert = (certificate_t* (*) (cert_payload_t*))get_cert;
293 this->public.get_cert_encoding = (cert_encoding_t (*) (cert_payload_t*))get_cert_encoding;
294 this->public.get_hash = (chunk_t (*) (cert_payload_t*))get_hash;
295 this->public.get_url = (char* (*) (cert_payload_t*))get_url;
296
297 this->critical = FALSE;
298 this->next_payload = NO_PAYLOAD;
299 this->payload_length = CERT_PAYLOAD_HEADER_LENGTH;
300 this->data = chunk_empty;
301 this->encoding = 0;
302 this->invalid_hash_and_url = FALSE;
303
304 return &this->public;
305 }
306
307 /*
308 * Described in header
309 */
310 cert_payload_t *cert_payload_create_from_cert(certificate_t *cert)
311 {
312 private_cert_payload_t *this = (private_cert_payload_t*)cert_payload_create();
313
314 switch (cert->get_type(cert))
315 {
316 case CERT_X509:
317 this->encoding = ENC_X509_SIGNATURE;
318 break;
319 default:
320 DBG1(DBG_ENC, "embedding %N certificate in payload failed",
321 certificate_type_names, cert->get_type(cert));
322 free(this);
323 return NULL;
324 }
325 this->data = cert->get_encoding(cert);
326 this->payload_length = CERT_PAYLOAD_HEADER_LENGTH + this->data.len;
327 return &this->public;
328 }
329
330 /*
331 * Described in header
332 */
333 cert_payload_t *cert_payload_create_from_hash_and_url(chunk_t hash, char *url)
334 {
335 private_cert_payload_t *this = (private_cert_payload_t*)cert_payload_create();
336 chunk_t url_chunk;
337
338 this->encoding = ENC_X509_HASH_AND_URL;
339
340 url_chunk.ptr = url;
341 url_chunk.len = strlen(url) + 1;
342
343 this->data = chunk_cat("cc", hash, url_chunk);
344 this->payload_length = CERT_PAYLOAD_HEADER_LENGTH + this->data.len;
345 return &this->public;
346 }
347