int FuzzerTestOneInput(const uint8_t *buf, size_t len) { CMS_ContentInfo *cms; BIO *in; if (len == 0) return 0; in = BIO_new(BIO_s_mem()); OPENSSL_assert((size_t)BIO_write(in, buf, len) == len); cms = d2i_CMS_bio(in, NULL); if (cms != NULL) { BIO *out = BIO_new(BIO_s_null()); i2d_CMS_bio(out, cms); BIO_free(out); CMS_ContentInfo_free(cms); } BIO_free(in); ERR_clear_error(); return 0; }
int main( int argc, char * argv [] ) { enum { ARG_IN_DATA_FILE_IX = 1, ARG_OUT_SIG_FILE_IX = 2, ARG_KEY_FILE_IX = 3, ARG_KEY_PASS_IX = 4, ARG_KEY_CERT_FILE_IX = 5, ARG_FIRST_EXTRA_CERT_FILE_IX = 6 }; int exit_code = 0; /* -------------------------------------------------------------- */ /* initialization */ exit_code = 1; SSL_load_error_strings(); SSL_library_init(); /* -------------------------------------------------------------- */ /* command-line processing */ exit_code = 2; if ( argc < 6 ) { fprintf( stderr, "usage: %s IN_DATA_FILE OUT_SIG_FILE" " KEY_FILE KEY_PASS KEY_CERT EXTRA_CERTS...\n", argv[0] ); return 1; } BIO * in_data_file = BIO_new_file( argv[ ARG_IN_DATA_FILE_IX ], "rb" ); if ( ! in_data_file ) { perror( argv[ ARG_IN_DATA_FILE_IX ] ); goto end; } BIO * out_sig_file = BIO_new_file( argv[ ARG_OUT_SIG_FILE_IX ], "wb" ); if ( ! out_sig_file ) { perror( argv[ ARG_OUT_SIG_FILE_IX ] ); goto free_in_data_file; } BIO * key_file = BIO_new_file( argv[ ARG_KEY_FILE_IX ], "rb" ); if ( ! key_file ) { perror( argv[ ARG_KEY_FILE_IX ] ); goto free_out_sig_file; } char * pw = argv[ ARG_KEY_PASS_IX ]; /* fprintf( stderr, "pw='%s'\n", pw ); */ BIO * key_cert_file = BIO_new_file( argv[ ARG_KEY_CERT_FILE_IX ], "rb" ); if ( ! key_cert_file ) { perror( argv[ ARG_KEY_CERT_FILE_IX ] ); goto free_key_file; } BIO * * extra_cert_files = NULL; int num_extra_cert_files = argc - ARG_FIRST_EXTRA_CERT_FILE_IX; if ( num_extra_cert_files > 0 ) { extra_cert_files = calloc( num_extra_cert_files, sizeof( BIO * ) ); if ( ! extra_cert_files ) { perror( "extra_cert_files" ); goto free_key_cert_file; } for ( int i = 0; i < num_extra_cert_files; ++i ) { extra_cert_files[i] = BIO_new_file( argv[ ARG_FIRST_EXTRA_CERT_FILE_IX + i ], "rb" ); if ( ! extra_cert_files[i] ) { perror( argv[ ARG_FIRST_EXTRA_CERT_FILE_IX + i ] ); goto free_key_cert_file; } } } /* -------------------------------------------------------------- */ /* processing */ exit_code = 3; #define FAIL( msg, dest ) \ do { \ fprintf( stderr, "error: " msg "\n" ); \ goto dest; \ } while ( 0 ) EVP_PKEY * key = PEM_read_bio_PrivateKey( key_file, NULL, NULL, pw ); if ( ! key ) FAIL( "reading private key", free_extra_cert_files ); X509 * key_cert = PEM_read_bio_X509( key_cert_file, NULL, NULL, NULL ); if ( ! key_cert ) FAIL( "reading signing cert", free_key ); STACK_OF(X509) * extra_certs = NULL; if ( num_extra_cert_files > 0 ) { int success = 1; extra_certs = sk_X509_new_null(); if ( ! extra_certs ) FAIL( "allocating stack for extra certs", free_key_cert ); for ( int i = 0; i < num_extra_cert_files; ++i ) { X509 * tmp = PEM_read_bio_X509( extra_cert_files[i], NULL, NULL, NULL ); if ( ! tmp ) { fprintf( stderr, "error reading '%s'\n", argv[ ARG_FIRST_EXTRA_CERT_FILE_IX + i ] ); success = 0; break; } if ( ! sk_X509_push( extra_certs, tmp ) ) { fprintf( stderr, "error pushing '%s'\n", argv[ ARG_FIRST_EXTRA_CERT_FILE_IX + i ] ); success = 0; X509_free( tmp ); break; } } if ( ! success ) FAIL( "could not read extra certs", free_extra_certs ); } CMS_ContentInfo * ci = CMS_sign( key_cert, key, extra_certs, in_data_file, CMS_DETACHED | CMS_BINARY ); /* if ( 1 != PEM_write_bio_CMS( out_sig_file, ci ) ) FAIL( "could not write signature in PEM", free_ci ); */ if ( 1 != i2d_CMS_bio( out_sig_file, ci ) ) FAIL( "could not write signature in DER", free_ci ); /* -------------------------------------------------------------- */ /* success */ exit_code = 0; /* -------------------------------------------------------------- */ /* cleanup */ free_ci: CMS_ContentInfo_free( ci ); free_extra_certs: sk_X509_pop_free( extra_certs, &X509_free ); free_key_cert: X509_free( key_cert ); free_key: EVP_PKEY_free( key ); free_extra_cert_files: for ( int i = 0; i < num_extra_cert_files; ++i ) BIO_vfree( extra_cert_files[ i ] ); free( extra_cert_files ); free_key_cert_file: BIO_vfree( key_cert_file ); free_key_file: BIO_vfree( key_file ); free_out_sig_file: BIO_vfree( out_sig_file ); free_in_data_file: BIO_vfree( in_data_file ); ERR_print_errors_fp( stderr ); ERR_remove_state( /* pid= */ 0 ); ENGINE_cleanup(); CONF_modules_unload( /* all= */ 1 ); EVP_cleanup(); ERR_free_strings(); CRYPTO_cleanup_all_ex_data(); end: return exit_code; }
int32_t mz_crypt_sign(uint8_t *message, int32_t message_size, uint8_t *cert_data, int32_t cert_data_size, const char *cert_pwd, uint8_t **signature, int32_t *signature_size) { PKCS12 *p12 = NULL; EVP_PKEY *evp_pkey = NULL; BUF_MEM *buf_mem = NULL; BIO *cert_bio = NULL; BIO *message_bio = NULL; BIO *signature_bio = NULL; CMS_ContentInfo *cms = NULL; CMS_SignerInfo *signer_info = NULL; STACK_OF(X509) *ca_stack = NULL; X509 *cert = NULL; int32_t result = 0; int32_t err = MZ_OK; if (message == NULL || cert_data == NULL || signature == NULL || signature_size == NULL) return MZ_PARAM_ERROR; mz_crypt_init(); *signature = NULL; *signature_size = 0; cert_bio = BIO_new_mem_buf(cert_data, cert_data_size); if (d2i_PKCS12_bio(cert_bio, &p12) == NULL) err = MZ_SIGN_ERROR; if (err == MZ_OK) result = PKCS12_parse(p12, cert_pwd, &evp_pkey, &cert, &ca_stack); if (result) { cms = CMS_sign(NULL, NULL, ca_stack, NULL, CMS_BINARY | CMS_PARTIAL); if (cms) signer_info = CMS_add1_signer(cms, cert, evp_pkey, EVP_sha256(), 0); if (signer_info == NULL) { err = MZ_SIGN_ERROR; } else { message_bio = BIO_new_mem_buf(message, message_size); signature_bio = BIO_new(BIO_s_mem()); result = CMS_final(cms, message_bio, NULL, CMS_BINARY); if (result) result = i2d_CMS_bio(signature_bio, cms); if (result) { BIO_flush(signature_bio); BIO_get_mem_ptr(signature_bio, &buf_mem); *signature_size = buf_mem->length; *signature = MZ_ALLOC(buf_mem->length); memcpy(*signature, buf_mem->data, buf_mem->length); } #if 0 BIO *yy = BIO_new_file("xyz", "wb"); BIO_write(yy, *signature, *signature_size); BIO_flush(yy); BIO_free(yy); #endif } } if (!result) err = MZ_SIGN_ERROR; if (cms) CMS_ContentInfo_free(cms); if (signature_bio) BIO_free(signature_bio); if (cert_bio) BIO_free(cert_bio); if (message_bio) BIO_free(message_bio); if (p12) PKCS12_free(p12); if (err != MZ_OK && *signature != NULL) { MZ_FREE(*signature); *signature = NULL; *signature_size = 0; } return err; }
GBytes *cms_sign(GBytes *content, const gchar *certfile, const gchar *keyfile, gchar **interfiles, GError **error) { GError *ierror = NULL; BIO *incontent = BIO_new_mem_buf((void *)g_bytes_get_data(content, NULL), g_bytes_get_size(content)); BIO *outsig = BIO_new(BIO_s_mem()); X509 *signcert = NULL; EVP_PKEY *pkey = NULL; STACK_OF(X509) *intercerts = NULL; CMS_ContentInfo *cms = NULL; GBytes *res = NULL; int flags = CMS_DETACHED | CMS_BINARY; g_return_val_if_fail(content != NULL, NULL); g_return_val_if_fail(certfile != NULL, NULL); g_return_val_if_fail(keyfile != NULL, NULL); g_return_val_if_fail(error == NULL || *error == NULL, NULL); signcert = load_cert(certfile, &ierror); if (signcert == NULL) { g_propagate_error(error, ierror); goto out; } pkey = load_key(keyfile, &ierror); if (pkey == NULL) { g_propagate_error(error, ierror); goto out; } intercerts = sk_X509_new_null(); for (gchar **intercertpath = interfiles; intercertpath && *intercertpath != NULL; intercertpath++) { X509 *intercert = load_cert(*intercertpath, &ierror); if (intercert == NULL) { g_propagate_error(error, ierror); goto out; } sk_X509_push(intercerts, intercert); } cms = CMS_sign(signcert, pkey, intercerts, incontent, flags); if (cms == NULL) { unsigned long err; const gchar *data; int errflags; err = ERR_get_error_line_data(NULL, NULL, &data, &errflags); g_set_error( error, R_SIGNATURE_ERROR, R_SIGNATURE_ERROR_INVALID, "failed to create signature: %s", (errflags & ERR_TXT_STRING) ? data : ERR_error_string(err, NULL)); goto out; } if (!i2d_CMS_bio(outsig, cms)) { g_set_error_literal( error, R_SIGNATURE_ERROR, R_SIGNATURE_ERROR_SERIALIZE_SIG, "failed to serialize signature"); goto out; } res = bytes_from_bio(outsig); if (!res) { g_set_error_literal( error, R_SIGNATURE_ERROR, R_SIGNATURE_ERROR_UNKNOWN, "Read zero bytes"); goto out; } /* keyring was given, perform verification to obtain trust chain */ if (r_context()->config->keyring_path) { g_autoptr(CMS_ContentInfo) vcms = NULL; g_autoptr(X509_STORE) store = NULL; STACK_OF(X509) *verified_chain = NULL; g_message("Keyring given, doing signature verification"); if (!cms_verify(content, res, &vcms, &store, &ierror)) { g_propagate_error(error, ierror); res = NULL; goto out; } if (!cms_get_cert_chain(vcms, store, &verified_chain, &ierror)) { g_propagate_error(error, ierror); res = NULL; goto out; } for (int i = 0; i < sk_X509_num(verified_chain); i++) { const ASN1_TIME *expiry_time; struct tm *next_month; time_t now; time_t comp; time(&now); next_month = gmtime(&now); next_month->tm_mon += 1; if (next_month->tm_mon == 12) next_month->tm_mon = 0; comp = timegm(next_month); expiry_time = X509_get0_notAfter(sk_X509_value(verified_chain, i)); /* Check if expiry time is within last month */ if (X509_cmp_current_time(expiry_time) == 1 && X509_cmp_time(expiry_time, &comp) == -1) { char buf[BUFSIZ]; X509_NAME_oneline(X509_get_subject_name(sk_X509_value(verified_chain, i)), buf, sizeof buf); g_warning("Certificate %d (%s) will exipre in less than a month!", i + 1, buf); } } sk_X509_pop_free(verified_chain, X509_free); } else { g_message("No keyring given, skipping signature verification"); } out: ERR_print_errors_fp(stdout); BIO_free_all(incontent); BIO_free_all(outsig); return res; }