diff --git a/osslsigncode.c b/osslsigncode.c
index 9d7cdb2..cdc2884 100644
--- a/osslsigncode.c
+++ b/osslsigncode.c
@@ -419,6 +419,20 @@ static SpcSpOpusInfo* createOpus(const char *desc, const char *url)
 	return info;
 }
 
+static unsigned int asn1_simple_hdr_len(const unsigned char *p, unsigned int len) {
+	if (len <= 2 || p[0] > 0x31)
+		return 0;
+	return (p[1]&0x80) ? (2 + (p[1]&0x7f)) : 2;
+}
+
+static void tohex(const unsigned char *v, unsigned char *b, int len)
+{
+	int i;
+	for(i=0; i<len; i++)
+		sprintf((char*)b+i*2, "%02X", v[i]);
+	b[i*2] = 0x00;
+}
+
 #ifdef ENABLE_CURL
 
 static int blob_has_nl = 0;
@@ -1179,7 +1193,6 @@ static gboolean msi_prehash(GsfInfile *infile, gchar *dirname, BIO *hash)
 }
 #endif
 
-
 /**
  * msi_handle_dir performs a direct copy of the input MSI file in infile to a new
  * output file in outfile.  While copying, it also writes all file content to the
@@ -1237,16 +1250,212 @@ static gboolean msi_handle_dir(GsfInfile *infile, GsfOutfile *outole, BIO *hash)
 
 	return TRUE;
 }
+
+/*
+ * msi_verify_file checks whether or not the signature of infile is valid.
+ */
+static int msi_verify_file(GsfInfile *infile) {
+	GsfInput *sig = NULL;
+	GsfInput *exsig = NULL;
+	gchar decoded[0x40];
+	int i, ret = 0;
+
+	for (i = 0; i < gsf_infile_num_children(infile); i++) {
+		GsfInput *child = gsf_infile_child_by_index(infile, i);
+		const guint8 *name = (const guint8*)gsf_input_name(child);
+		msi_decode(name, decoded);
+		if (!g_strcmp0(decoded, "\05DigitalSignature"))
+			sig = child;
+		if (!g_strcmp0(decoded, "\05MsiDigitalSignatureEx"))
+			exsig = child;
+	}
+	if (sig == NULL) {
+		printf("MSI file has no signature\n\n");
+		ret = 1;
+		goto out;
+	}
+
+	unsigned long inlen = (unsigned long) gsf_input_remaining(sig);
+	unsigned char *indata = malloc(inlen);
+	if (gsf_input_read(sig, inlen, indata) == NULL) {
+		ret = 1;
+		goto out;
+	}
+
+	unsigned char *exdata = NULL;
+	unsigned long exlen = 0;
+	if (exsig != NULL) {
+		exlen = (unsigned long) gsf_input_remaining(exsig);
+		exdata = malloc(exlen);
+		if (gsf_input_read(exsig, exlen, exdata) == NULL) {
+			ret = 1;
+			goto out;
+		}
+	}
+
+	int mdtype = -1;
+	unsigned char mdbuf[EVP_MAX_MD_SIZE];
+	unsigned char cmdbuf[EVP_MAX_MD_SIZE];
+	unsigned char cexmdbuf[EVP_MAX_MD_SIZE];
+	unsigned char hexbuf[EVP_MAX_MD_SIZE*2+1];
+	PKCS7 *p7 = NULL;
+	BIO *bio = NULL;
+
+	ASN1_OBJECT *indir_objid = OBJ_txt2obj(SPC_INDIRECT_DATA_OBJID, 1);
+	const unsigned char *blob = (unsigned char *)indata;
+	p7 = d2i_PKCS7(NULL, &blob, inlen);
+	if (p7 && PKCS7_type_is_signed(p7) && !OBJ_cmp(p7->d.sign->contents->type, indir_objid) && p7->d.sign->contents->d.other->type == V_ASN1_SEQUENCE) {
+		ASN1_STRING *astr = p7->d.sign->contents->d.other->value.sequence;
+		const unsigned char *p = astr->data;
+		SpcIndirectDataContent *idc = d2i_SpcIndirectDataContent(NULL, &p, astr->length);
+		if (idc) {
+			if (idc->messageDigest && idc->messageDigest->digest && idc->messageDigest->digestAlgorithm) {
+				mdtype = OBJ_obj2nid(idc->messageDigest->digestAlgorithm->algorithm);
+				memcpy(mdbuf, idc->messageDigest->digest->data, idc->messageDigest->digest->length);
+			}
+			SpcIndirectDataContent_free(idc);
+		}
+		ASN1_OBJECT_free(indir_objid);
+		if (p7 && mdtype == -1) {
+			PKCS7_free(p7);
+			p7 = NULL;
+		}
+	}
+
+	if (mdtype == -1) {
+		printf("Failed to extract current message digest\n\n");
+		ret = 1;
+		goto out;
+	}
+
+	if (p7 == NULL) {
+		printf("Failed to read PKCS7 signature from DigitalSignature section\n\n");
+		ret = 1;
+		goto out;
+	}
+
+	printf("Message digest algorithm         : %s\n", OBJ_nid2sn(mdtype));
+
+	const EVP_MD *md = EVP_get_digestbynid(mdtype);
+	BIO *hash = BIO_new(BIO_f_md());
+	BIO_set_md(hash, md);
+	BIO_push(hash, BIO_new(BIO_s_null()));
+
+	if (exsig) {
+		/*
+		 * Until libgsf can read more MSI metadata, we can't
+		 * really verify them by plowing through the file.
+		 * Verifying files signed by osslsigncode itself works,
+		 * though!
+		 *
+		 * For now, the compromise is to use the hash given
+		 * by the file, which is equivalent to verifying a
+		 * non-MsiDigitalSignatureEx signature from a security
+		 * pespective, because we'll only be calculating the
+		 * file content hashes ourselves.
+		 */
+#ifdef GSF_CAN_READ_MSI_METADATA
+		BIO *prehash = BIO_new(BIO_f_md());
+		BIO_set_md(prehash, md);
+		BIO_push(prehash, BIO_new(BIO_s_null()));
+
+		if (!msi_prehash(infile, NULL, prehash)) {
+			ret = 1;
+			goto out;
+		}
+
+		BIO_gets(prehash, (char*)cexmdbuf, EVP_MAX_MD_SIZE);
+		BIO_write(hash, (char*)cexmdbuf, EVP_MD_size(md));
+#else
+		BIO_write(hash, (char *)exdata, EVP_MD_size(md));
+#endif
+	}
+
+	if (!msi_handle_dir(infile, NULL, hash)) {
+		ret = 1;
+		goto out;
+	}
+
+	BIO_gets(hash, (char*)cmdbuf, EVP_MAX_MD_SIZE);
+	tohex(cmdbuf, hexbuf, EVP_MD_size(md));
+	int mdok = !memcmp(mdbuf, cmdbuf, EVP_MD_size(md));
+	if (!mdok) ret = 1;
+	printf("Calculated DigitalSignature      : %s", hexbuf);
+	if (mdok) {
+		printf("\n");
+	} else {
+		tohex(mdbuf, hexbuf, EVP_MD_size(md));
+		printf("    MISMATCH!!! FILE HAS %s\n", hexbuf);
+	}
+
+#ifdef GSF_CAN_READ_MSI_METADATA
+	if (exsig && exdata) {
+		tohex(cexmdbuf, hexbuf, EVP_MD_size(md));
+		int exok = !memcmp(exdata, cexmdbuf, MIN(EVP_MD_size(md), exlen));
+		if (!mdok) ret = 1;
+		printf("Calculated MsiDigitalSignatureEx : %s", hexbuf);
+		if (mdok) {
+			printf("\n");
+		} else {
+			tohex(exdata, hexbuf, EVP_MD_size(md));
+			printf("    MISMATCH!!! FILE HAS %s\n", hexbuf);
+		}
+	}
 #endif
 
-static void tohex(const unsigned char *v, unsigned char *b, int len)
-{
-	int i;
-	for(i=0; i<len; i++)
-		sprintf((char*)b+i*2, "%02X", v[i]);
-	b[i*2] = 0x00;
+	printf("\n");
+
+	int seqhdrlen = asn1_simple_hdr_len(p7->d.sign->contents->d.other->value.sequence->data,
+										p7->d.sign->contents->d.other->value.sequence->length);
+	bio = BIO_new_mem_buf(p7->d.sign->contents->d.other->value.sequence->data + seqhdrlen,
+						  p7->d.sign->contents->d.other->value.sequence->length - seqhdrlen);
+	X509_STORE *store = X509_STORE_new();
+	int verok = PKCS7_verify(p7, p7->d.sign->cert, store, bio, NULL, PKCS7_NOVERIFY);
+	BIO_free(bio);	
+	/* XXX: add more checks here (attributes, timestamp, etc) */
+	printf("Signature verification: %s\n\n", verok ? "ok" : "failed");
+	if (!verok) {
+		ERR_print_errors_fp(stdout);
+		ret = 1;
+	}
+
+	STACK_OF(X509) *signers = PKCS7_get0_signers(p7, NULL, 0);
+	printf("Number of signers: %d\n", sk_X509_num(signers));
+	for (i=0; i<sk_X509_num(signers); i++) {
+		X509 *cert = sk_X509_value(signers, i);
+		char *subject = X509_NAME_oneline(X509_get_subject_name(cert), NULL, 0);
+		char *issuer = X509_NAME_oneline(X509_get_issuer_name(cert), NULL, 0);
+		printf("\tSigner #%d:\n\t\tSubject : %s\n\t\tIssuer  : %s\n", i, subject, issuer);
+		OPENSSL_free(subject);
+		OPENSSL_free(issuer);
+	}
+	sk_X509_free(signers);
+
+	printf("\nNumber of certificates: %d\n", sk_X509_num(p7->d.sign->cert));
+	for (i=0; i<sk_X509_num(p7->d.sign->cert); i++) {
+		X509 *cert = sk_X509_value(p7->d.sign->cert, i);
+		char *subject = X509_NAME_oneline(X509_get_subject_name(cert), NULL, 0);
+		char *issuer = X509_NAME_oneline(X509_get_issuer_name(cert), NULL, 0);
+		printf("\tCert #%d:\n\t\tSubject : %s\n\t\tIssuer  : %s\n", i, subject, issuer);
+		OPENSSL_free(subject);
+		OPENSSL_free(issuer);
+    }
+
+	printf("\n");
+
+out:
+	free(indata);
+	free(exdata);
+
+	if (store)
+		X509_STORE_free(store);
+	if (p7)
+		PKCS7_free(p7);
+
+	return ret;
 }
 
+#endif
 
 static void calc_pe_digest(BIO *bio, const EVP_MD *md, unsigned char *mdbuf,
 						   unsigned int peheader, int pe32plus, unsigned int fileend)
@@ -1283,12 +1492,6 @@ static void calc_pe_digest(BIO *bio, const EVP_MD *md, unsigned char *mdbuf,
 }
 
 
-static unsigned int asn1_simple_hdr_len(const unsigned char *p, unsigned int len) {
-	if (len <= 2 || p[0] > 0x31)
-		return 0;
-	return (p[1]&0x80) ? (2 + (p[1]&0x7f)) : 2;
-}
-
 static void	extract_page_hash (SpcAttributeTypeAndOptionalValue *obj,
 							   unsigned char **ph, unsigned int *phlen, int *phtype)
 {
@@ -1886,16 +2089,18 @@ int main(int argc, char **argv)
 		src = gsf_input_stdio_new(infile, NULL);
 		if (!src)
 			DO_EXIT_1("Error opening file %s", infile);
+		ole = gsf_infile_msole_new(src, NULL);
 
-		if (cmd == CMD_SIGN || cmd == CMD_REMOVE) {
-			sink = gsf_output_stdio_new(outfile, NULL);
-			if (!sink)
-				DO_EXIT_1("Error opening output file %s", outfile);
-
-			ole = gsf_infile_msole_new(src, NULL);
-			outole = gsf_outfile_msole_new(sink);
+		if (cmd == CMD_VERIFY) {
+			ret = msi_verify_file(ole);
+			goto skip_signing;
 		}
 
+		sink = gsf_output_stdio_new(outfile, NULL);
+		if (!sink)
+			DO_EXIT_1("Error opening output file %s", outfile);
+		outole = gsf_outfile_msole_new(sink);
+
 #ifndef NO_MSI_DIGITALSIGNATUREEX
 		/*
 		 * MsiDigitalSignatureEx is an enhanced signature type that