static void signature_loopback(void) { GBytes *content = read_file("test/openssl-ca/manifest", NULL); GBytes *sig = NULL; g_assert_nonnull(content); sig = cms_sign(content, r_context()->certpath, r_context()->keypath, NULL); g_assert_nonnull(sig); g_assert_true(cms_verify(content, sig, NULL)); ((char *)g_bytes_get_data(content, NULL))[0] = 0x00; g_assert_false(cms_verify(content, sig, NULL)); g_bytes_unref(content); g_bytes_unref(sig); }
static void signature_verify(void) { GBytes *content = read_file("test/openssl-ca/manifest", NULL); GBytes *sig = read_file("test/openssl-ca/manifest-r1.sig", NULL); g_assert_nonnull(content); g_assert_nonnull(sig); g_assert_true(cms_verify(content, sig, NULL)); g_bytes_unref(content); g_bytes_unref(sig); }
/** * Verify image using downloaded signature * * @v image Image to verify * @v signature Image containing signature * @v name Required common name, or NULL to allow any name * @ret rc Return status code */ int imgverify ( struct image *image, struct image *signature, const char *name ) { size_t len; void *data; struct cms_signature *sig; time_t now; int rc; /* Mark image as untrusted */ image_untrust ( image ); /* Copy signature to internal memory */ len = signature->len; data = malloc ( len ); if ( ! data ) { rc = -ENOMEM; goto err_alloc; } copy_from_user ( data, signature->data, 0, len ); /* Parse signature */ if ( ( rc = cms_signature ( data, len, &sig ) ) != 0 ) goto err_parse; /* Free internal copy of signature */ free ( data ); data = NULL; /* Use signature to verify image */ now = time ( NULL ); if ( ( rc = cms_verify ( sig, image->data, image->len, name, now, NULL ) ) != 0 ) goto err_verify; /* Drop reference to signature */ cms_put ( sig ); sig = NULL; /* Mark image as trusted */ image_trust ( image ); syslog ( LOG_NOTICE, "Image \"%s\" signature OK\n", image->name ); return 0; err_verify: cms_put ( sig ); err_parse: free ( data ); err_alloc: syslog ( LOG_ERR, "Image \"%s\" signature bad: %s\n", image->name, strerror ( rc ) ); return rc; }
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; }