* src/crypto/crypto.c: Added crypto.sign and crypto.verify methods
that wrap EVP_Sign and EVP_Verify function families, using code
derived from Dave Cridland's PyOpenSSL branch.
* test/test_crypto.py: Added unit tests for crypto.sign and
crypto.verify.
diff --git a/src/crypto/crypto.c b/src/crypto/crypto.c
index decf722..dd279cf 100644
--- a/src/crypto/crypto.c
+++ b/src/crypto/crypto.c
@@ -2,6 +2,7 @@
* crypto.c
*
* Copyright (C) AB Strakt 2001, All rights reserved
+ * Copyright (C) Keyphrene 2004, All rights reserved
* Copyright (C) Jean-Paul Calderone 2008-2009, All rights reserved
*
* Main file of crypto sub module.
@@ -545,6 +546,101 @@
return NULL;
}
+static char crypto_sign_doc[] = "\n\
+Sign data with a digest\n\
+\n\
+@param pkey: Pkey to sign with\n\
+@param data: data to be signed\n\
+@param digest: message digest to use\n\
+@return: signature\n\
+";
+
+static PyObject *
+crypto_sign(PyObject *spam, PyObject *args)
+{
+ PyObject *buffer;
+ crypto_PKeyObj *pkey;
+ char *data = NULL;
+ char *digest_name;
+ int err;
+ unsigned int sig_len;
+ const EVP_MD *digest;
+ EVP_MD_CTX md_ctx;
+ unsigned char sig_buf[512];
+
+ if (!PyArg_ParseTuple(args, "O!ss:sign", &crypto_PKey_Type,
+ &pkey, &data, &digest_name))
+ return NULL;
+
+ if ((digest = EVP_get_digestbyname(digest_name)) == NULL)
+ {
+ PyErr_SetString(PyExc_ValueError, "No such digest method");
+ return NULL;
+ }
+
+ EVP_SignInit (&md_ctx, digest);
+ EVP_SignUpdate (&md_ctx, data, strlen(data));
+ sig_len = sizeof(sig_buf);
+ err = EVP_SignFinal (&md_ctx, sig_buf, &sig_len, pkey->pkey);
+
+ if (err != 1) {
+ exception_from_error_queue(crypto_Error);
+ return NULL;
+ }
+
+ buffer = PyString_FromStringAndSize(sig_buf, sig_len);
+ return buffer;
+}
+
+static char crypto_verify_doc[] = "\n\
+Verify a signature\n\
+\n\
+@param cert: signing certificate (X509 object)\n\
+@param signature: signature returned by sign function\n\
+@param data: data to be verified\n\
+@param digest: message digest to use\n\
+@return: None if the signature is correct, raise exception otherwise\n\
+";
+
+static PyObject *
+crypto_verify(PyObject *spam, PyObject *args)
+{
+ crypto_X509Obj *cert;
+ unsigned char *signature;
+ int sig_len;
+ char *data, *digest_name;
+ int err;
+ const EVP_MD *digest;
+ EVP_MD_CTX md_ctx;
+ EVP_PKEY *pkey;
+
+ if (!PyArg_ParseTuple(args, "O!t#ss:verify", &crypto_X509_Type, &cert, &signature, &sig_len,
+ &data, &digest_name))
+ return NULL;
+
+ if ((digest = EVP_get_digestbyname(digest_name)) == NULL){
+ PyErr_SetString(PyExc_ValueError, "No such digest method");
+ return NULL;
+ }
+ pkey=X509_get_pubkey(cert->x509);
+ if (pkey == NULL) {
+ PyErr_SetString(PyExc_ValueError, "No public key");
+ return NULL;
+ }
+
+ EVP_VerifyInit (&md_ctx, digest);
+ EVP_VerifyUpdate (&md_ctx, data, strlen((char*)data));
+ err = EVP_VerifyFinal (&md_ctx, signature, sig_len, pkey);
+ EVP_PKEY_free (pkey);
+
+ if (err != 1) {
+ exception_from_error_queue(crypto_Error);
+ return NULL;
+ }
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
/* Methods in the OpenSSL.crypto module (i.e. none) */
static PyMethodDef crypto_methods[] = {
@@ -557,6 +653,8 @@
{ "dump_certificate_request", (PyCFunction)crypto_dump_certificate_request, METH_VARARGS, crypto_dump_certificate_request_doc },
{ "load_pkcs7_data", (PyCFunction)crypto_load_pkcs7_data, METH_VARARGS, crypto_load_pkcs7_data_doc },
{ "load_pkcs12", (PyCFunction)crypto_load_pkcs12, METH_VARARGS, crypto_load_pkcs12_doc },
+ { "sign", (PyCFunction)crypto_sign, METH_VARARGS, crypto_sign_doc },
+ { "verify", (PyCFunction)crypto_verify, METH_VARARGS, crypto_verify_doc },
{ "X509_verify_cert_error_string", (PyCFunction)crypto_X509_verify_cert_error_string, METH_VARARGS, crypto_X509_verify_cert_error_string_doc },
{ "_exception_from_error_queue", (PyCFunction)crypto_exception_from_error_queue, METH_NOARGS, crypto_exception_from_error_queue_doc },
{ NULL, NULL }