OLD | NEW |
1 /* asn_mime.c */ | 1 /* asn_mime.c */ |
2 /* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL | 2 /* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL |
3 * project. | 3 * project. |
4 */ | 4 */ |
5 /* ==================================================================== | 5 /* ==================================================================== |
6 * Copyright (c) 1999-2008 The OpenSSL Project. All rights reserved. | 6 * Copyright (c) 1999-2008 The OpenSSL Project. All rights reserved. |
7 * | 7 * |
8 * Redistribution and use in source and binary forms, with or without | 8 * Redistribution and use in source and binary forms, with or without |
9 * modification, are permitted provided that the following conditions | 9 * modification, are permitted provided that the following conditions |
10 * are met: | 10 * are met: |
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
52 * | 52 * |
53 */ | 53 */ |
54 | 54 |
55 #include <stdio.h> | 55 #include <stdio.h> |
56 #include <ctype.h> | 56 #include <ctype.h> |
57 #include "cryptlib.h" | 57 #include "cryptlib.h" |
58 #include <openssl/rand.h> | 58 #include <openssl/rand.h> |
59 #include <openssl/x509.h> | 59 #include <openssl/x509.h> |
60 #include <openssl/asn1.h> | 60 #include <openssl/asn1.h> |
61 #include <openssl/asn1t.h> | 61 #include <openssl/asn1t.h> |
| 62 #include "asn1_locl.h" |
62 | 63 |
63 /* Generalised MIME like utilities for streaming ASN1. Although many | 64 /* Generalised MIME like utilities for streaming ASN1. Although many |
64 * have a PKCS7/CMS like flavour others are more general purpose. | 65 * have a PKCS7/CMS like flavour others are more general purpose. |
65 */ | 66 */ |
66 | 67 |
67 /* MIME format structures | 68 /* MIME format structures |
68 * Note that all are translated to lower case apart from | 69 * Note that all are translated to lower case apart from |
69 * parameter values. Quotes are stripped off | 70 * parameter values. Quotes are stripped off |
70 */ | 71 */ |
71 | 72 |
72 typedef struct { | 73 typedef struct { |
73 char *param_name; /* Param name e.g. "micalg" */ | 74 char *param_name; /* Param name e.g. "micalg" */ |
74 char *param_value; /* Param value e.g. "sha1" */ | 75 char *param_value; /* Param value e.g. "sha1" */ |
75 } MIME_PARAM; | 76 } MIME_PARAM; |
76 | 77 |
77 DECLARE_STACK_OF(MIME_PARAM) | 78 DECLARE_STACK_OF(MIME_PARAM) |
78 IMPLEMENT_STACK_OF(MIME_PARAM) | 79 IMPLEMENT_STACK_OF(MIME_PARAM) |
79 | 80 |
80 typedef struct { | 81 typedef struct { |
81 char *name; /* Name of line e.g. "content-type" */ | 82 char *name; /* Name of line e.g. "content-type" */ |
82 char *value; /* Value of line e.g. "text/plain" */ | 83 char *value; /* Value of line e.g. "text/plain" */ |
83 STACK_OF(MIME_PARAM) *params; /* Zero or more parameters */ | 84 STACK_OF(MIME_PARAM) *params; /* Zero or more parameters */ |
84 } MIME_HEADER; | 85 } MIME_HEADER; |
85 | 86 |
86 DECLARE_STACK_OF(MIME_HEADER) | 87 DECLARE_STACK_OF(MIME_HEADER) |
87 IMPLEMENT_STACK_OF(MIME_HEADER) | 88 IMPLEMENT_STACK_OF(MIME_HEADER) |
88 | 89 |
| 90 static int asn1_output_data(BIO *out, BIO *data, ASN1_VALUE *val, int flags, |
| 91 const ASN1_ITEM *it); |
89 static char * strip_ends(char *name); | 92 static char * strip_ends(char *name); |
90 static char * strip_start(char *name); | 93 static char * strip_start(char *name); |
91 static char * strip_end(char *name); | 94 static char * strip_end(char *name); |
92 static MIME_HEADER *mime_hdr_new(char *name, char *value); | 95 static MIME_HEADER *mime_hdr_new(char *name, char *value); |
93 static int mime_hdr_addparam(MIME_HEADER *mhdr, char *name, char *value); | 96 static int mime_hdr_addparam(MIME_HEADER *mhdr, char *name, char *value); |
94 static STACK_OF(MIME_HEADER) *mime_parse_hdr(BIO *bio); | 97 static STACK_OF(MIME_HEADER) *mime_parse_hdr(BIO *bio); |
95 static int mime_hdr_cmp(const MIME_HEADER * const *a, | 98 static int mime_hdr_cmp(const MIME_HEADER * const *a, |
96 const MIME_HEADER * const *b); | 99 const MIME_HEADER * const *b); |
97 static int mime_param_cmp(const MIME_PARAM * const *a, | 100 static int mime_param_cmp(const MIME_PARAM * const *a, |
98 const MIME_PARAM * const *b); | 101 const MIME_PARAM * const *b); |
99 static void mime_param_free(MIME_PARAM *param); | 102 static void mime_param_free(MIME_PARAM *param); |
100 static int mime_bound_check(char *line, int linelen, char *bound, int blen); | 103 static int mime_bound_check(char *line, int linelen, char *bound, int blen); |
101 static int multi_split(BIO *bio, char *bound, STACK_OF(BIO) **ret); | 104 static int multi_split(BIO *bio, char *bound, STACK_OF(BIO) **ret); |
102 static int strip_eol(char *linebuf, int *plen); | 105 static int strip_eol(char *linebuf, int *plen); |
103 static MIME_HEADER *mime_hdr_find(STACK_OF(MIME_HEADER) *hdrs, char *name); | 106 static MIME_HEADER *mime_hdr_find(STACK_OF(MIME_HEADER) *hdrs, char *name); |
104 static MIME_PARAM *mime_param_find(MIME_HEADER *hdr, char *name); | 107 static MIME_PARAM *mime_param_find(MIME_HEADER *hdr, char *name); |
105 static void mime_hdr_free(MIME_HEADER *hdr); | 108 static void mime_hdr_free(MIME_HEADER *hdr); |
106 | 109 |
107 #define MAX_SMLEN 1024 | 110 #define MAX_SMLEN 1024 |
108 #define mime_debug(x) /* x */ | 111 #define mime_debug(x) /* x */ |
109 | 112 |
| 113 /* Output an ASN1 structure in BER format streaming if necessary */ |
| 114 |
| 115 int i2d_ASN1_bio_stream(BIO *out, ASN1_VALUE *val, BIO *in, int flags, |
| 116 const ASN1_ITEM *it) |
| 117 { |
| 118 /* If streaming create stream BIO and copy all content through it */ |
| 119 if (flags & SMIME_STREAM) |
| 120 { |
| 121 BIO *bio, *tbio; |
| 122 bio = BIO_new_NDEF(out, val, it); |
| 123 if (!bio) |
| 124 { |
| 125 ASN1err(ASN1_F_I2D_ASN1_BIO_STREAM,ERR_R_MALLOC_FAILURE)
; |
| 126 return 0; |
| 127 } |
| 128 SMIME_crlf_copy(in, bio, flags); |
| 129 (void)BIO_flush(bio); |
| 130 /* Free up successive BIOs until we hit the old output BIO */ |
| 131 do |
| 132 { |
| 133 tbio = BIO_pop(bio); |
| 134 BIO_free(bio); |
| 135 bio = tbio; |
| 136 } while (bio != out); |
| 137 } |
| 138 /* else just write out ASN1 structure which will have all content |
| 139 * stored internally |
| 140 */ |
| 141 else |
| 142 ASN1_item_i2d_bio(it, out, val); |
| 143 return 1; |
| 144 } |
| 145 |
110 /* Base 64 read and write of ASN1 structure */ | 146 /* Base 64 read and write of ASN1 structure */ |
111 | 147 |
112 static int B64_write_ASN1(BIO *out, ASN1_VALUE *val, BIO *in, int flags, | 148 static int B64_write_ASN1(BIO *out, ASN1_VALUE *val, BIO *in, int flags, |
113 const ASN1_ITEM *it) | 149 const ASN1_ITEM *it) |
114 { | 150 { |
115 BIO *b64; | 151 BIO *b64; |
116 int r; | 152 int r; |
117 b64 = BIO_new(BIO_f_base64()); | 153 b64 = BIO_new(BIO_f_base64()); |
118 if(!b64) | 154 if(!b64) |
119 { | 155 { |
120 ASN1err(ASN1_F_B64_WRITE_ASN1,ERR_R_MALLOC_FAILURE); | 156 ASN1err(ASN1_F_B64_WRITE_ASN1,ERR_R_MALLOC_FAILURE); |
121 return 0; | 157 return 0; |
122 } | 158 } |
123 /* prepend the b64 BIO so all data is base64 encoded. | 159 /* prepend the b64 BIO so all data is base64 encoded. |
124 */ | 160 */ |
125 out = BIO_push(b64, out); | 161 out = BIO_push(b64, out); |
126 » r = ASN1_item_i2d_bio(it, out, val); | 162 » r = i2d_ASN1_bio_stream(out, val, in, flags, it); |
127 (void)BIO_flush(out); | 163 (void)BIO_flush(out); |
128 BIO_pop(out); | 164 BIO_pop(out); |
129 BIO_free(b64); | 165 BIO_free(b64); |
130 return r; | 166 return r; |
131 } | 167 } |
132 | 168 |
| 169 /* Streaming ASN1 PEM write */ |
| 170 |
| 171 int PEM_write_bio_ASN1_stream(BIO *out, ASN1_VALUE *val, BIO *in, int flags, |
| 172 const char *hdr, |
| 173 const ASN1_ITEM *it) |
| 174 { |
| 175 int r; |
| 176 BIO_printf(out, "-----BEGIN %s-----\n", hdr); |
| 177 r = B64_write_ASN1(out, val, in, flags, it); |
| 178 BIO_printf(out, "-----END %s-----\n", hdr); |
| 179 return r; |
| 180 } |
| 181 |
133 static ASN1_VALUE *b64_read_asn1(BIO *bio, const ASN1_ITEM *it) | 182 static ASN1_VALUE *b64_read_asn1(BIO *bio, const ASN1_ITEM *it) |
134 { | 183 { |
135 BIO *b64; | 184 BIO *b64; |
136 ASN1_VALUE *val; | 185 ASN1_VALUE *val; |
137 if(!(b64 = BIO_new(BIO_f_base64()))) { | 186 if(!(b64 = BIO_new(BIO_f_base64()))) { |
138 ASN1err(ASN1_F_B64_READ_ASN1,ERR_R_MALLOC_FAILURE); | 187 ASN1err(ASN1_F_B64_READ_ASN1,ERR_R_MALLOC_FAILURE); |
139 return 0; | 188 return 0; |
140 } | 189 } |
141 bio = BIO_push(b64, bio); | 190 bio = BIO_push(b64, bio); |
142 val = ASN1_item_d2i_bio(it, bio, NULL); | 191 val = ASN1_item_d2i_bio(it, bio, NULL); |
143 if(!val) | 192 if(!val) |
144 ASN1err(ASN1_F_B64_READ_ASN1,ASN1_R_DECODE_ERROR); | 193 ASN1err(ASN1_F_B64_READ_ASN1,ASN1_R_DECODE_ERROR); |
145 (void)BIO_flush(bio); | 194 (void)BIO_flush(bio); |
146 bio = BIO_pop(bio); | 195 bio = BIO_pop(bio); |
147 BIO_free(b64); | 196 BIO_free(b64); |
148 return val; | 197 return val; |
149 } | 198 } |
150 | 199 |
151 /* Generate the MIME "micalg" parameter from RFC3851, RFC4490 */ | 200 /* Generate the MIME "micalg" parameter from RFC3851, RFC4490 */ |
152 | 201 |
153 static int asn1_write_micalg(BIO *out, STACK_OF(X509_ALGOR) *mdalgs) | 202 static int asn1_write_micalg(BIO *out, STACK_OF(X509_ALGOR) *mdalgs) |
154 { | 203 { |
155 » int i, have_unknown = 0, write_comma, md_nid; | 204 » const EVP_MD *md; |
| 205 » int i, have_unknown = 0, write_comma, ret = 0, md_nid; |
156 have_unknown = 0; | 206 have_unknown = 0; |
157 write_comma = 0; | 207 write_comma = 0; |
158 for (i = 0; i < sk_X509_ALGOR_num(mdalgs); i++) | 208 for (i = 0; i < sk_X509_ALGOR_num(mdalgs); i++) |
159 { | 209 { |
160 if (write_comma) | 210 if (write_comma) |
161 BIO_write(out, ",", 1); | 211 BIO_write(out, ",", 1); |
162 write_comma = 1; | 212 write_comma = 1; |
163 md_nid = OBJ_obj2nid(sk_X509_ALGOR_value(mdalgs, i)->algorithm); | 213 md_nid = OBJ_obj2nid(sk_X509_ALGOR_value(mdalgs, i)->algorithm); |
| 214 md = EVP_get_digestbynid(md_nid); |
| 215 if (md && md->md_ctrl) |
| 216 { |
| 217 int rv; |
| 218 char *micstr; |
| 219 rv = md->md_ctrl(NULL, EVP_MD_CTRL_MICALG, 0, &micstr); |
| 220 if (rv > 0) |
| 221 { |
| 222 BIO_puts(out, micstr); |
| 223 OPENSSL_free(micstr); |
| 224 continue; |
| 225 } |
| 226 if (rv != -2) |
| 227 goto err; |
| 228 } |
164 switch(md_nid) | 229 switch(md_nid) |
165 { | 230 { |
166 case NID_sha1: | 231 case NID_sha1: |
167 BIO_puts(out, "sha1"); | 232 BIO_puts(out, "sha1"); |
168 break; | 233 break; |
169 | 234 |
170 case NID_md5: | 235 case NID_md5: |
171 BIO_puts(out, "md5"); | 236 BIO_puts(out, "md5"); |
172 break; | 237 break; |
173 | 238 |
174 case NID_sha256: | 239 case NID_sha256: |
175 BIO_puts(out, "sha-256"); | 240 BIO_puts(out, "sha-256"); |
176 break; | 241 break; |
177 | 242 |
178 case NID_sha384: | 243 case NID_sha384: |
179 BIO_puts(out, "sha-384"); | 244 BIO_puts(out, "sha-384"); |
180 break; | 245 break; |
181 | 246 |
182 case NID_sha512: | 247 case NID_sha512: |
183 BIO_puts(out, "sha-512"); | 248 BIO_puts(out, "sha-512"); |
184 break; | 249 break; |
185 | 250 |
| 251 case NID_id_GostR3411_94: |
| 252 BIO_puts(out, "gostr3411-94"); |
| 253 goto err; |
| 254 break; |
| 255 |
186 default: | 256 default: |
187 if (have_unknown) | 257 if (have_unknown) |
188 write_comma = 0; | 258 write_comma = 0; |
189 else | 259 else |
190 { | 260 { |
191 BIO_puts(out, "unknown"); | 261 BIO_puts(out, "unknown"); |
192 have_unknown = 1; | 262 have_unknown = 1; |
193 } | 263 } |
194 break; | 264 break; |
195 | 265 |
196 } | 266 } |
197 } | 267 } |
198 | 268 |
199 » return 1; | 269 » ret = 1; |
| 270 » err: |
| 271 |
| 272 » return ret; |
200 | 273 |
201 } | 274 } |
202 | 275 |
203 /* SMIME sender */ | 276 /* SMIME sender */ |
204 | 277 |
205 int int_smime_write_ASN1(BIO *bio, ASN1_VALUE *val, BIO *data, int flags, | 278 int SMIME_write_ASN1(BIO *bio, ASN1_VALUE *val, BIO *data, int flags, |
206 int ctype_nid, int econt_nid, | 279 int ctype_nid, int econt_nid, |
207 STACK_OF(X509_ALGOR) *mdalgs, | 280 STACK_OF(X509_ALGOR) *mdalgs, |
208 asn1_output_data_fn *data_fn, | |
209 const ASN1_ITEM *it) | 281 const ASN1_ITEM *it) |
210 { | 282 { |
211 char bound[33], c; | 283 char bound[33], c; |
212 int i; | 284 int i; |
213 const char *mime_prefix, *mime_eol, *cname = "smime.p7m"; | 285 const char *mime_prefix, *mime_eol, *cname = "smime.p7m"; |
214 const char *msg_type=NULL; | 286 const char *msg_type=NULL; |
215 if (flags & SMIME_OLDMIME) | 287 if (flags & SMIME_OLDMIME) |
216 mime_prefix = "application/x-pkcs7-"; | 288 mime_prefix = "application/x-pkcs7-"; |
217 else | 289 else |
218 mime_prefix = "application/pkcs7-"; | 290 mime_prefix = "application/pkcs7-"; |
(...skipping 17 matching lines...) Expand all Loading... |
236 BIO_printf(bio, "Content-Type: multipart/signed;"); | 308 BIO_printf(bio, "Content-Type: multipart/signed;"); |
237 BIO_printf(bio, " protocol=\"%ssignature\";", mime_prefix); | 309 BIO_printf(bio, " protocol=\"%ssignature\";", mime_prefix); |
238 BIO_puts(bio, " micalg=\""); | 310 BIO_puts(bio, " micalg=\""); |
239 asn1_write_micalg(bio, mdalgs); | 311 asn1_write_micalg(bio, mdalgs); |
240 BIO_printf(bio, "\"; boundary=\"----%s\"%s%s", | 312 BIO_printf(bio, "\"; boundary=\"----%s\"%s%s", |
241 bound, mime_eol, mime_eol); | 313 bound, mime_eol, mime_eol); |
242 BIO_printf(bio, "This is an S/MIME signed message%s%s", | 314 BIO_printf(bio, "This is an S/MIME signed message%s%s", |
243 mime_eol, mime_eol); | 315 mime_eol, mime_eol); |
244 /* Now write out the first part */ | 316 /* Now write out the first part */ |
245 BIO_printf(bio, "------%s%s", bound, mime_eol); | 317 BIO_printf(bio, "------%s%s", bound, mime_eol); |
246 » » if (!data_fn(bio, data, val, flags, it)) | 318 » » if (!asn1_output_data(bio, data, val, flags, it)) |
247 return 0; | 319 return 0; |
248 BIO_printf(bio, "%s------%s%s", mime_eol, bound, mime_eol); | 320 BIO_printf(bio, "%s------%s%s", mime_eol, bound, mime_eol); |
249 | 321 |
250 /* Headers for signature */ | 322 /* Headers for signature */ |
251 | 323 |
252 BIO_printf(bio, "Content-Type: %ssignature;", mime_prefix); | 324 BIO_printf(bio, "Content-Type: %ssignature;", mime_prefix); |
253 BIO_printf(bio, " name=\"smime.p7s\"%s", mime_eol); | 325 BIO_printf(bio, " name=\"smime.p7s\"%s", mime_eol); |
254 BIO_printf(bio, "Content-Transfer-Encoding: base64%s", | 326 BIO_printf(bio, "Content-Transfer-Encoding: base64%s", |
255 mime_eol); | 327 mime_eol); |
256 BIO_printf(bio, "Content-Disposition: attachment;"); | 328 BIO_printf(bio, "Content-Disposition: attachment;"); |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
289 BIO_printf(bio, " smime-type=%s;", msg_type); | 361 BIO_printf(bio, " smime-type=%s;", msg_type); |
290 BIO_printf(bio, " name=\"%s\"%s", cname, mime_eol); | 362 BIO_printf(bio, " name=\"%s\"%s", cname, mime_eol); |
291 BIO_printf(bio, "Content-Transfer-Encoding: base64%s%s", | 363 BIO_printf(bio, "Content-Transfer-Encoding: base64%s%s", |
292 mime_eol, mime_eol); | 364 mime_eol, mime_eol); |
293 if (!B64_write_ASN1(bio, val, data, flags, it)) | 365 if (!B64_write_ASN1(bio, val, data, flags, it)) |
294 return 0; | 366 return 0; |
295 BIO_printf(bio, "%s", mime_eol); | 367 BIO_printf(bio, "%s", mime_eol); |
296 return 1; | 368 return 1; |
297 } | 369 } |
298 | 370 |
299 #if 0 | |
300 | |
301 /* Handle output of ASN1 data */ | 371 /* Handle output of ASN1 data */ |
302 | 372 |
303 | 373 |
304 static int asn1_output_data(BIO *out, BIO *data, ASN1_VALUE *val, int flags, | 374 static int asn1_output_data(BIO *out, BIO *data, ASN1_VALUE *val, int flags, |
305 const ASN1_ITEM *it) | 375 const ASN1_ITEM *it) |
306 { | 376 { |
307 BIO *tmpbio; | 377 BIO *tmpbio; |
308 const ASN1_AUX *aux = it->funcs; | 378 const ASN1_AUX *aux = it->funcs; |
309 ASN1_STREAM_ARG sarg; | 379 ASN1_STREAM_ARG sarg; |
310 | 380 |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
343 { | 413 { |
344 tmpbio = BIO_pop(sarg.ndef_bio); | 414 tmpbio = BIO_pop(sarg.ndef_bio); |
345 BIO_free(sarg.ndef_bio); | 415 BIO_free(sarg.ndef_bio); |
346 sarg.ndef_bio = tmpbio; | 416 sarg.ndef_bio = tmpbio; |
347 } | 417 } |
348 | 418 |
349 return 1; | 419 return 1; |
350 | 420 |
351 } | 421 } |
352 | 422 |
353 #endif | |
354 | |
355 /* SMIME reader: handle multipart/signed and opaque signing. | 423 /* SMIME reader: handle multipart/signed and opaque signing. |
356 * in multipart case the content is placed in a memory BIO | 424 * in multipart case the content is placed in a memory BIO |
357 * pointed to by "bcont". In opaque this is set to NULL | 425 * pointed to by "bcont". In opaque this is set to NULL |
358 */ | 426 */ |
359 | 427 |
360 ASN1_VALUE *SMIME_read_ASN1(BIO *bio, BIO **bcont, const ASN1_ITEM *it) | 428 ASN1_VALUE *SMIME_read_ASN1(BIO *bio, BIO **bcont, const ASN1_ITEM *it) |
361 { | 429 { |
362 BIO *asnin; | 430 BIO *asnin; |
363 STACK_OF(MIME_HEADER) *headers = NULL; | 431 STACK_OF(MIME_HEADER) *headers = NULL; |
364 STACK_OF(BIO) *parts = NULL; | 432 STACK_OF(BIO) *parts = NULL; |
(...skipping 500 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
865 { | 933 { |
866 c = *p; | 934 c = *p; |
867 if (c == '\n') | 935 if (c == '\n') |
868 is_eol = 1; | 936 is_eol = 1; |
869 else if (c != '\r') | 937 else if (c != '\r') |
870 break; | 938 break; |
871 } | 939 } |
872 *plen = len; | 940 *plen = len; |
873 return is_eol; | 941 return is_eol; |
874 } | 942 } |
OLD | NEW |