Skip to content
This repository has been archived by the owner on Mar 28, 2023. It is now read-only.

Commit

Permalink
Add possibility to sign PKCS7 with a non-default digest.
Browse files Browse the repository at this point in the history
An optional parameter "algo" is added to SMIME.sign().
This is what is done by "-md" option in the command
"openssl smime -sign -md <digest_name> ..."
  • Loading branch information
KonstantinShemyak committed Nov 28, 2016
1 parent 55c673d commit 7defbbf
Show file tree
Hide file tree
Showing 3 changed files with 55 additions and 10 deletions.
14 changes: 10 additions & 4 deletions M2Crypto/SMIME.py
Expand Up @@ -226,20 +226,26 @@ def decrypt(self, pkcs7, flags=0):
raise SMIME_Error(Err.get_error())
return blob

def sign(self, data_bio, flags=0):
# type: (BIO.BIO, int) -> PKCS7
def sign(self, data_bio, flags=0, algo='sha1'):
# type: (BIO.BIO, int, Optional[str]) -> PKCS7
if not hasattr(self, 'pkey'):
raise SMIME_Error('no private key: use load_key()')

hash = getattr(m2, algo, None)

if hash is None:
raise SMIME_Error('no such hash algorithm %s' % algo)

if hasattr(self, 'x509_stack'):
pkcs7 = m2.pkcs7_sign1(self.x509._ptr(), self.pkey._ptr(),
self.x509_stack._ptr(),
data_bio._ptr(), flags)
data_bio._ptr(), hash(), flags)
if pkcs7 is None:
raise SMIME_Error(Err.get_error())
return PKCS7(pkcs7, 1)
else:
pkcs7 = m2.pkcs7_sign0(self.x509._ptr(), self.pkey._ptr(),
data_bio._ptr(), flags)
data_bio._ptr(), hash(), flags)
if pkcs7 is None:
raise SMIME_Error(Err.get_error())
return PKCS7(pkcs7, 1)
Expand Down
26 changes: 20 additions & 6 deletions SWIG/_pkcs7.i
Expand Up @@ -95,17 +95,31 @@ PyObject *pkcs7_decrypt(PKCS7 *pkcs7, EVP_PKEY *pkey, X509 *cert, int flags) {
}
%}

%threadallow pkcs7_sign0;
%threadallow pkcs7_sign1;
%inline %{
PKCS7 *pkcs7_sign0(X509 *x509, EVP_PKEY *pkey, BIO *bio, int flags) {
return PKCS7_sign(x509, pkey, NULL, bio, flags);
PKCS7 *pkcs7_sign1(X509 *x509, EVP_PKEY *pkey, STACK_OF(X509) *stack, BIO *bio, EVP_MD *hash, int flags) {

PKCS7 *p7 = PKCS7_sign(NULL, NULL, stack, bio, flags | PKCS7_STREAM);
if (p7 == NULL) {
PyErr_SetString(_pkcs7_err, ERR_reason_error_string(ERR_get_error()));
return NULL;
}
if (PKCS7_sign_add_signer(p7, x509, pkey, hash, flags) == NULL) {
PyErr_SetString(_pkcs7_err, ERR_reason_error_string(ERR_get_error()));
return NULL;
}
if (PKCS7_final(p7, bio, flags) != 1) {
PyErr_SetString(_pkcs7_err, ERR_reason_error_string(ERR_get_error()));
return NULL;
}
return p7;
}
%}

%threadallow pkcs7_sign1;
%threadallow pkcs7_sign0;
%inline %{
PKCS7 *pkcs7_sign1(X509 *x509, EVP_PKEY *pkey, STACK_OF(X509) *stack, BIO *bio, int flags) {
return PKCS7_sign(x509, pkey, stack, bio, flags);
PKCS7 *pkcs7_sign0(X509 *x509, EVP_PKEY *pkey, BIO *bio, EVP_MD *hash, int flags) {
return pkcs7_sign1(x509, pkey, NULL, bio, hash, flags);
}
%}

Expand Down
25 changes: 25 additions & 0 deletions tests/test_smime.py
Expand Up @@ -67,6 +67,31 @@ def test_sign(self):
s.write(out, p7, BIO.MemoryBuffer(self.cleartext))
return out

def test_sign_unknown_digest(self):
buf = BIO.MemoryBuffer(self.cleartext)
s = SMIME.SMIME()
s.load_key('tests/signer_key.pem', 'tests/signer.pem')
self.assertRaises(SMIME.SMIME_Error, s.sign,
buf, SMIME.PKCS7_DETACHED, 'invalid digest name')

def test_sign_nondefault_digest(self):
buf = BIO.MemoryBuffer(self.cleartext)
s = SMIME.SMIME()
s.load_key('tests/signer_key.pem', 'tests/signer.pem')
p7 = s.sign(buf, flags=SMIME.PKCS7_DETACHED, algo='sha512')
self.assertEqual(p7.type(), SMIME.PKCS7_SIGNED)

def test_sign_with_stack(self):
buf = BIO.MemoryBuffer(self.cleartext)
s = SMIME.SMIME()
s.load_key('tests/signer_key.pem', 'tests/signer.pem')
cert = X509.load_cert('tests/server.pem')
stack = X509.X509_Stack()
stack.push(cert)
s.set_x509_stack(stack)
p7 = s.sign(buf, flags=SMIME.PKCS7_DETACHED, algo='sha512')
self.assertEqual(p7.type(), SMIME.PKCS7_SIGNED)

def test_store_load_info(self):
st = X509.X509_Store()
with self.assertRaises(X509.X509Error):
Expand Down

3 comments on commit 7defbbf

@TerryRen
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

awesome, could you please release a new version of this function?
btw: Which version of openssl should I use? (openssl smime -md xxxxxxx)
thanks a lot

@mcepl
Copy link
Owner

@mcepl mcepl commented on 7defbbf Mar 14, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It will be in 0.26.1, which will happen sometime soon, really™.

@TerryRen
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh,this is so cool!

Please sign in to comment.