| 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 |