1 /* smimeutil.h - Utility functions for performing S/MIME signatures 2 * and encryption. 3 * 4 * Copyright (c) 1999 Sampo Kellomaki <sampo@iki.fi>, All Rights Reserved. 5 * License: This software may be distributed under the same license 6 * terms as openssl (i.e. free, but mandatory attribution). 7 * 8 * Official web site: http://www.bacus.pt/Net_SSLeay/smime.html 9 * $Id: smimeutil.h,v 1.1 2009-08-30 15:09:26 sampo Exp $ 10 * 11 * 11.9.1999, Created. --Sampo 12 * 1.10.1999, added error codes. --Sampo 13 * 5.10.1999, split interface to character based PEM interface (old) and 14 * data structure based internal interface. --Sampo 15 * 29.10.1999, added prototypes for certification authority. --Sampo 16 * 17 * This module has been developed to support a Lingo XTRA that is supposed 18 * to provide crypto functionality. It may, however, be useful for other 19 * purposes as well. See also smime.c for command line tool. 20 * 21 * Memory management: most routines malloc the results. Freeing them 22 * is application's responsibility. I use libc malloc, but if in doubt 23 * it might be safer to just leak the memory (i.e. don't ever free 24 * it). The library never attempts to free arguments passed to it 25 * (i.e. you can safely pass in pointers to buffers on stack or 26 * string constants). 27 * 28 * ERROR HANDLING 29 * 30 * Most library functions return NULL (pointer) or -1 (length) upon 31 * error. If you want to know in more detail what happened you should 32 * call smime_get_errors() function. Most error messages are 33 * meaningless to an average application and its user. Meaningful 34 * error messages start by two digit number. Any message not starting 35 * by number should be assumed to be (in this order) 36 * - lack of memory ("no memory?" is a strong indication of this, but 37 * could also mean that the malloc arena has been corrupted, beware!) 38 * - application passed in bad arguments (application programmer error) 39 * - internal library error (library programmer error or OpenSSL error) 40 * 41 * These meaningful error codes exist 42 * 01 bad private key file or password, private key couldn't be 43 * decrypted (wrong file? bad line endings?) 44 * 02 bad PKCS12 file format (perhaps wrong file? corrupt file?) 45 * 03 bad PKCS12 import password 46 * 04 bad X509_REQ (pem)file format (perhaps wrong file or bad line endings) 47 * 05 mismatched X509 certificate and private key (wrong files?) 48 * 06 bad DN component name (must be one of the registered ones) 49 * 07 bad attribute name (must be one of the registered ones) 50 * 08 bad characters in DN or attribute value 51 * 09 missing `=' in DN component or attribute value specification or 52 * specification otherwise badly formatted (perhaps missing newlines?) 53 * 10 bad X509_REQ (pem)file format (perhaps wrong file or bad line endings) 54 * 11 corrupt p7m message (perhaps whitespace or newlines were added) 55 * 12 message decryption failed. Either message was not encrypted 56 * for the recipient as indicated by certificate (issuer and serial 57 * number fields do not match recipient info) or private key 58 * could not open the encryption, i.e. wrong private key. Could 59 * also indicate sophisticated message corruption. 60 * 13 No signatures found in signature blob. Perhaps its corrupt or 61 * is really encrypted blob instead. 62 * 14 signature did not verify. Check for message corruption or 63 * unexpected white space (esp. if message was clear signed) 64 * 15 signed entity did not contain any signed data (corrupt entity?) 65 * 16 missing mime header, e.g. Content-type: multipart/... 66 * 67 */ 68 69 #ifndef _SMIMEUTIL_H 70 #define _SMIMEUTIL_H 71 #ifdef __cplusplus 72 extern "C" { 73 #endif 74 75 #define SMIME_VERSION "smimeutils v0.7 17.11.1999" 76 77 #include <stdio.h> /* snprintf() */ 78 #if defined(SMIME_INTERNALS) && !defined(__DIRECTORYSCRIPT__) 79 # include <openssl/bio.h> 80 # include <openssl/x509.h> 81 # include <openssl/evp.h> 82 # include <openssl/pkcs12.h> 83 #endif 84 85 #ifndef DSEXPORT 86 #define DSEXPORT 87 #endif 88 89 /* ======= M I M E M U L T I P A R T M A N I P U L A T I O N ======= */ 90 91 /* Create MIME multipart/mixed mime entity containing some text and 92 * then up to 3 attachmets. All attachments are base64 encoded so they 93 * can be binary if needed. */ 94 95 DSEXPORT char* 96 mime_mk_multipart(const char* text, 97 const char* file1, int len1, const char* type1, const char* name1, 98 const char* file2, int len2, const char* type2, const char* name2, 99 const char* file3, int len3, const char* type3, const char* name3); 100 101 /* Create multipart/signed entity (given that detached sig already exists, 102 * see also smime_clear_sign()) */ 103 104 DSEXPORT char* /* returns smime encoded clear sig blob, or NULL if error */ 105 smime_mk_multipart_signed(const char* mime_entity, const char* sig_entity); 106 107 /* Finds boundary marker from `Content-type: multipart/...; boundary=sep' 108 * header and splits the multiparts into array parts. Lengths of each 109 * part go to lengths array. If parts is NULL, just returns the number 110 * of parts found. Memory for each part is obtained from Malloc. Only 111 * one level of multipart encoding is interpretted, i.e. if one of the 112 * contained parts happens to be a multipart, it needs to be separately 113 * interpretted on a second pass. 114 * 115 * *** WARNING: this is not totally robust and mime compliant, improvements 116 * welcome. --Sampo 117 */ 118 119 DSEXPORT int /* returns number of parts, -1 on error */ 120 mime_split_multipart(const char* entity, 121 int max_parts, /* how big following arrays are */ 122 char* parts[], /* NULL --> just count the parts */ 123 int lengths[]); 124 125 /* Add headers */ 126 127 DSEXPORT char* mime_raw_entity(const char* text, const char* type); 128 129 /* Apply base64 and add headers */ 130 131 DSEXPORT char* mime_base64_entity(const char* data, int len, const char* type); 132 133 /* CR->CRLF (Mac) and LF->CRLF (Unix) conversion */ 134 135 DSEXPORT char* mime_canon(const char* s); 136 137 /* ============= S I G N I N G & E N C R Y P T I O N ============= */ 138 139 /* Typically signing and encryption involves a sequence of calls like 140 * 141 * msg = smime_encrypt(pubkey, 142 * smime_clear_sign(privkey, password, 143 * mime_mk_multipart(text, file1, type1, name1, 144 * NULL, NULL, NULL, 145 * NULL, NULL, NULL))); 146 */ 147 148 /* Sign a mime entity, such as produced by mime_mk_multipart(). Signature 149 * is stored as separate mime entity so the message proper stays visible. */ 150 151 DSEXPORT char* /* Returns malloc'd buffer which caller must free. NULL on error */ 152 smime_clear_sign(const char* privkey, 153 const char* password, 154 const char* mime_entity); 155 156 /* Sign a mime entity, such as produced by mime_mk_multipart(). Signature 157 * and entity are output as one base64 blob so the entity is not trivially 158 * visible. */ 159 160 DSEXPORT char* /* Returns malloc'd buffer which caller must free. NULL on error */ 161 smime_sign(const char* privkey, 162 const char* password, 163 const char* mime_entity); 164 165 /* Encrypt a mime entity such as produced by smime_clear_sign(). */ 166 167 DSEXPORT char* /* Returns malloc'd buffer which caller must free. NULL on error */ 168 smime_encrypt(const char* pubkey, const char* mime_entity); 169 170 /* ============= S I G N A T U R E V E R I F I C A T I O N ==============*/ 171 /* ============= A N D D E C R Y P T I O N ============================= */ 172 173 /* Typically receiver has to know in what order the signature and encryption 174 * were applied (usually encryption is outermost) and then call these 175 * functions in right order, e.g: 176 */ 177 178 DSEXPORT int /* returns size of data, -1 on error */ 179 smime_decrypt(const char* privkey, 180 const char* passwd, 181 const char* enc_entity, 182 char** data_out); 183 184 DSEXPORT long /* return serial on success, -1 on failure */ 185 smime_get_signer_info(const char* signed_entity, 186 int info_ix, /* 0 = first signer. Used to iterate */ 187 char** issuer); /* DN of the issuer */ 188 189 /* smime_verify_signature can be used to verify both signed entities 190 * and clear signatures. In the first case you must pass NULL on 191 * detached_data parameter. The contents of signed entity are malloc'd 192 * and returned (i.e. you must free it). In the clear sig case, detached 193 * data is returned without malloc. */ 194 195 DSEXPORT char* /* returns contents of the signed message, NULL if error */ 196 smime_verify_signature(const char* pubkey, 197 const char* sig_entity, /* signed entity 198 or just the sigature */ 199 const char* detached_data, /* possibly NULL */ 200 int detached_data_len); 201 202 DSEXPORT int /* returns -1 if error, 0 if verfy fail, and 1 if verify OK */ 203 smime_verify_cert(const char* ca_cert_pem, const char* cert_pem); 204 205 DSEXPORT char* /* returns pem encoded certificate, or NULL if error */ 206 smime_ca(const char* ca_id_pem, 207 const char* passwd, 208 const char* req_pem, 209 const char* start_date, 210 const char* end_date, 211 long serial, 212 const char* basic_constraints, 213 const char* cert_type, 214 const char* key_usage, 215 const char* comment); 216 217 /* ============= K E Y G E N E R A T I O N ==============*/ 218 219 /* char** values are out parameters. They return malloced values. 220 * random is extra random number seed. passowrd is the password used 221 * to encrypt the private key. identifiaction is a newline separated list 222 * of attributes to include in certification request. Each line has 223 * format: `name=value\n' 224 */ 225 226 DSEXPORT int 227 smime_keygen(const char* dn, /* distinguished name to include in cert */ 228 const char* attr, /* additional attributes to send */ 229 const char* passwd, /* password for encrypting the private key */ 230 const char* comment, /* comment to include in self signed cert */ 231 char** priv, /* pem encoded private key */ 232 char** x509ss, /* pem encoded self signed cert */ 233 char** request); /* pem encoded certificate request */ 234 235 /* Convert pem formatted certificate and private key into PKCS12 236 * object suitable for importing to browsers. 237 * 238 * openssl pkcs12 -name "Test friendly name" -info -in cert.pem -inkey priv.pem -chain -export >pkcs12 239 */ 240 241 DSEXPORT int 242 smime_pem_to_pkcs12(const char* friendly_name, /* e.g. foo@bar.com */ 243 const char* x509_cert_pem, /* must have only one */ 244 const char* priv_key_pem, 245 const char* priv_passwd, /* used to open private key */ 246 const char* pkcs12_passwd, /* used to encrypt pkcs12 */ 247 char** pkcs12); 248 249 /* more generic version that allows inclusion of multiple certificates */ 250 251 DSEXPORT int 252 smime_pem_to_pkcs12_generic(const char* friendly_name, /* e.g. foo@bar.com */ 253 const char* x509_certs_pem, /* can have many */ 254 const char* priv_key_pem, 255 const char* priv_passwd, /* used to open private key */ 256 const char* pkcs12_passwd, /* used to encrypt pkcs12 */ 257 char** pkcs12); 258 259 /* Extract certificate(s) and public key(s) from PKCS12 structure. 260 * Can be used to extract only one or the other by passing NULL 261 * to appropriate OUT parameter. Can only extract last private key 262 * and last certificate (so beware if passing a certificate chain). 263 * 264 * openssl pkcs12 <foo.p12 265 */ 266 267 DSEXPORT int 268 smime_pkcs12_to_pem(const char* pkcs12, int pkcs12_len, 269 const char* pkcs12_passwd, /* used to decrypt pkcs12 */ 270 const char* priv_passwd, /* used to enc. private key */ 271 char** priv_key_pem, /* OUT private key */ 272 char** x509_cert_pem); /* OUT certificate */ 273 274 /* more generic because handles multiple certificates and private keys 275 in key bags */ 276 277 DSEXPORT int 278 smime_pkcs12_to_pem_generic(const char* pkcs12, int pkcs12_len, 279 const char* pkcs12_passwd, /* used to decrypt pkcs12 */ 280 const char* priv_passwd, /* used to enc. private key */ 281 char** priv_key_pem, /* OUT private key(s) */ 282 char** x509_cert_pem); /* OUT certificate(s) */ 283 284 /* Obtain some human readable descriptions of the certificate. This is 285 * important, for example, to verify if two certificates have the same 286 * public key modulus. 287 */ 288 289 DSEXPORT long /* return serial number, -1 on failure */ 290 smime_get_cert_info(const char* x509_cert_pem, 291 char** modulus, /* public key modulus */ 292 char** fingerprint); /* finger print that identifies */ 293 294 DSEXPORT char* /* public key modulus */ 295 smime_get_req_modulus(const char* request_pem); 296 297 /* Get distinguished name information from the certificate */ 298 299 DSEXPORT long /* return serial number, -1 on failure */ 300 smime_get_cert_names(const char* x509_cert_pem, 301 char** subject_DN, /* who the certificate belongs to */ 302 char** issuer_DN); /* who signed the certificate */ 303 304 DSEXPORT char* /* subject_DN - who the request belongs to */ 305 smime_get_req_name(const char* request_pem); 306 307 DSEXPORT char* /* string representation of some attributes */ 308 smime_get_req_attr(const char* request_pem); 309 310 /* Calculate a hash over any string (I use it for modulus) */ 311 312 DSEXPORT char* /* returns the md5 hash as hex dump */ 313 smime_md5(const char* modulus); 314 315 DSEXPORT char* /* 25 bit hash as string like `*Z4K67W*' or NULL if error */ 316 smime_get_req_hash(const char* request_pem); 317 318 #ifdef SMIME_INTERNALS 319 320 /* These are binary versions of the above functions. Generally these 321 * eat and return OpenSSL data structures instead of pem encodings. */ 322 323 DSEXPORT PKCS12* 324 x509_and_pkey_to_pkcs12(const char* friendly_name, /* e.g. foo@bar.com */ 325 X509* x509, /* cert that goes with the pkey */ 326 EVP_PKEY* pkey, /* private key */ 327 const char* pkcs12_passwd); /* used to encrypt pkcs12 */ 328 329 DSEXPORT int 330 pkcs12_to_x509_and_pkey(PKCS12* p12, 331 const char* pkcs12_passwd, /* used to decrypt pkcs12 */ 332 X509** x509_out, /* cert that goes with the pkey */ 333 EVP_PKEY** pkey_out); /* private key */ 334 335 DSEXPORT long /* return serial number, -1 on failure */ 336 get_cert_info(X509* x509, 337 char** modulus, /* public key modulus */ 338 char** fingerprint); /* finger print that identifies */ 339 340 DSEXPORT long /* return serial number, -1 on failure */ 341 get_cert_names(X509* x509, 342 char** subject_DN, /* who the certificate belongs to */ 343 char** issuer_DN); /* who signed the certificate */ 344 345 DSEXPORT char* /* public key modulus */ 346 get_req_modulus(X509_REQ* req); 347 348 DSEXPORT char* /* subject_DN - who the request belongs to */ 349 get_req_name(X509_REQ* req); 350 351 DSEXPORT char* /* new line separated list of attribute value pairs */ 352 get_req_attr(X509_REQ* req); 353 354 DSEXPORT char* /* hash, ready to print, or NULL if error */ 355 get_req_hash(X509_REQ* req); 356 357 DSEXPORT char* /* returns smime encoded clear signed blob, or NULL if error */ 358 clear_sign(X509* x509, EVP_PKEY* pkey, const char* mime_entity); 359 360 DSEXPORT char* /* returns smime blob, NULL if error */ 361 sign(X509* x509, EVP_PKEY* pkey, const char* mime_entity); 362 363 DSEXPORT int /* returns -1 if error, 0 if verfy fail, and 1 if verify OK */ 364 verify_cert(X509* ca_cert, X509* cert); 365 366 DSEXPORT char* encrypt1(X509* x509, const char* mime_entity); 367 368 DSEXPORT int /* return size of data, -1 on failure */ 369 decrypt(X509* x509, EVP_PKEY* pkey, const char* enc_entity, char** data_out); 370 371 DSEXPORT int 372 keygen(const char* dn, const char* attr, const char* comment, 373 EVP_PKEY** pkey_out, 374 X509** x509ss_out, 375 X509_REQ** req_out); 376 377 /* sign a request into a X509 certificate */ 378 379 DSEXPORT X509* /* returns signed certificate, or NULL if error */ 380 certification_authority(X509* ca_cert, 381 EVP_PKEY* ca_pkey, 382 X509_REQ* req, 383 const char* start_date, 384 const char* end_date, 385 long serial, 386 const char* basic_constraints, 387 const char* cert_type, 388 const char* key_usage, 389 const char* comment); 390 391 #endif 392 393 /* ======================= U T I L I T I E S ======================= */ 394 395 extern char randomfile[256]; 396 397 /* initializes EVP algorithm tables and injects randomness into 398 * system. If random file existed it is read as well and 0 (for 399 * success) is returned. If random file did not exist, it will be 400 * created (if permissions allow) and -1 is returned. On that occasion 401 * it is advisable to arrange some real randomness (such as movements of 402 * mouse, times between key presses, /dev/random, etc.) and call 403 * init again. */ 404 405 DSEXPORT int smime_init(const char* random_file, const char* randomness, int randlen); 406 407 /* encp=0 base64->binary, enc=1 binary->base64 */ 408 409 DSEXPORT int smime_base64(int encp, const char* data, int len, char** b64); 410 411 /* stores smime library level error. The buffer only has meaningful 412 * values if an error has happened. You must detect the error from 413 * return value of a function (NULL or -1) before looking here or 414 * calling smime_get_errors(). */ 415 extern char smime_error_buf[256]; 416 417 DSEXPORT char* smime_get_errors(); 418 DSEXPORT char* smime_hex(const char* data, int len); 419 DSEXPORT char* smime_dotted_hex(const char* data, int len); 420 421 /* ================= I N T E R N A L U T I L I T I E S ================ */ 422 423 #ifdef SMIME_INTERNALS 424 425 /* Hard coded mime separators. Hope the content will never have these. */ 426 427 #define SEP "42_is_the_answer" /* MIME multipart boundary separator */ 428 #define SIG "42_is_the_question" /* MIME multipart/signed boundary sep */ 429 430 /* To guard agains any macintosh brain damage where \n == \015 */ 431 432 #define CR "\015" 433 #define LF "\012" 434 #define CRLF "\015\012" 435 436 /* Initialize a memory BIO to have certain content */ 437 438 DSEXPORT BIO* set_read_BIO_from_buf(const char* buf, int len); 439 440 DSEXPORT int get_written_BIO_data(BIO* wbio, char** data); 441 442 /* Get private key from buffer full of encrypted stuff */ 443 444 DSEXPORT EVP_PKEY* open_private_key(const char* privatekey_pem, const char* password); 445 DSEXPORT int write_private_key(EVP_PKEY* pkey, const char* passwd, char** priv); 446 447 /* Extract a certificate from pem encoding */ 448 449 DSEXPORT X509* extract_certificate(const char* cert); 450 451 DSEXPORT int /* returns length of the PEM encoding */ 452 write_certificate(X509* x509, char** x509_cert_pem); 453 454 DSEXPORT X509_REQ* extract_request(const char* req); 455 DSEXPORT int write_request(X509_REQ* x509_req, char** x509_req_pem); 456 457 DSEXPORT PKCS12* load_PKCS12(const char* pkcs12, int pkcs12_len); 458 DSEXPORT int save_PKCS12(PKCS12* p12, char** pkcs12_out); 459 460 DSEXPORT int password_callback(char* buf, int buf_size, int x /*not used*/, void* password); 461 462 DSEXPORT char* concat(char* b, const char* s); 463 DSEXPORT char* concatmem(char* b, const char* s, int len); 464 465 /* WARNING: returned value can not be freed */ 466 DSEXPORT char* /* returns pointer to within buf. Buf is modified. */ 467 cut_pem_markers_off(char* buf, int len, char* algo_name); 468 469 DSEXPORT char* /* returns new buf */ 470 wrap_in_pem_markers(const char* buf, char* algo_name); 471 472 /* Adds some of the most commonly wanted extensions 473 * 474 * Examples: 475 * basic_constraints: CA:TRUE,pathlen:3 476 * cert_type: client,server,email,objsign,sslCA,emailCA,objCA 477 * key_usage: digitalSignature,nonRepudiation,keyEncipherment,dataEncipherment,keyAgreement,keyCertSign,cRLSign 478 * comment: dont trust me ;-) 479 */ 480 481 DSEXPORT int 482 add_some_X509v3_extensions(X509* cert, 483 const char* basic_constraints, 484 const char* cert_type, 485 const char* key_usage, 486 const char* comment); 487 488 /* Macro to make error reporting more friendly while still easy. */ 489 490 #if 1 491 # define GOTO_ERR(x) do{ snprintf(smime_error_buf, sizeof(smime_error_buf), \ 492 "%s (%s:%d)\n", (x), __FILE__, __LINE__); \ 493 smime_error_buf[sizeof(smime_error_buf)-1]='\0'; goto err; }while(0) 494 #else 495 # define GOTO_ERR(x) goto err 496 #endif 497 498 #undef DEBUGLOG 499 500 #ifdef DEBUGLOG 501 extern FILE* Log; 502 # define LOG(x) do{ if (Log) { fprintf(Log, "%s %d: %s\n", \ 503 __FILE__, __LINE__, (x)); fflush(Log); } }while(0) 504 # define LOG2(s,x) do{ if (Log) { fprintf(Log, "%s %d: " s "\n", \ 505 __FILE__, __LINE__, (x)); fflush(Log); } }while(0) 506 #else 507 #if !defined(DSPROXY) && !defined(__DIRECTORYSCRIPT__) 508 #define LOG(x) 509 #define LOG2(s,x) 510 #endif 511 #endif 512 513 #endif /* SMIME_INTERNALS */ 514 515 #ifdef __cplusplus 516 } 517 #endif 518 519 #endif /* _SMIMEUTIL_H */ 520