* This package is an SSL implementation written
* by Eric Young (eay@cryptsoft.com).
* The implementation was written so as to conform with Netscapes SSL.
- *
+ *
* This library is free for commercial and non-commercial use as long as
* the following conditions are aheared to. The following conditions
* apply to all code found in this distribution, be it the RC4, RSA,
* lhash, DES, etc., code; not just the SSL code. The SSL documentation
* included with this distribution is covered by the same copyright terms
* except that the holder is Tim Hudson (tjh@cryptsoft.com).
- *
+ *
* Copyright remains Eric Young's, and as such any Copyright notices in
* the code are not to be removed.
* If this package is used in a product, Eric Young should be given attribution
* as the author of the parts of the library used.
* This can be in the form of a textual message at program startup or
* in documentation (online or textual) provided with the package.
- *
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* Eric Young (eay@cryptsoft.com)"
* The word 'cryptographic' can be left out if the rouines from the library
* being used are not cryptographic related :-).
- * 4. If you include any Windows specific code (or a derivative thereof) from
+ * 4. If you include any Windows specific code (or a derivative thereof) from
* the apps directory (application code) you must include an acknowledgement:
* "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
- *
+ *
* THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
- *
+ *
* The licence and distribution terms for any publically available version or
* derivative of this code cannot be changed. i.e. this code cannot simply be
* copied and put under another distribution licence
* - all of EVP interface functionality minus `engine' support
* - all of PEM interface functionality
* - a simple SSL client
- *
+ *
* In addition, we are trying hard to provide not only an exact elisp
* copy of openssl, but also a _comprehensive_ one
*
- *
+ *
* * src/openssl.c: functions overview:
*
* - General
* ossl-connect - constructor for SSL connection objects
* ossl-finish - destructor of SSL connection objects
* ossl-pending - predicate if data is available for read
- * ossl-read -
+ * ossl-read -
* ossl-write -
* ossl-x509-get-subject
* ossl-x509-get-issuer
* ossl-sslcipher-name
* ossl-sslcipher-bits
*
- *
+ *
* * Todo (internally):
* - implement the usage of engines
* - implement X.509 stuff
* (ossl-ec-pkey-p pkey)
* ;; generate an ec (elliptic curve) key
* ;; Note: this is probably disabled in your openssl
- * (when (featurep 'openssl-ec)
+ * (when (featurep 'openssl-ec)
* (setq pkey (ossl-ec-generate-key))
* (ossl-ec-pkey-p pkey))
*
* Note: For these functions you must have enabled DH in your OpenSSL lib
* ;; not yet
*
- * - HYBRID
+ * - HYBRID
* (setq key (ossl-rsa-generate-key 2048 3))
* (setq enc (ossl-seal 'AES-256-ECB "a tight secret" key))
* (ossl-open 'AES-256-ECB (car enc) key (cadr enc) (caddr enc))
/*
*
* AUXILIARY
- *
+ *
*/
DEFUN("ossl-version", Fossl_version, 0, 0, 0, /*
Return a descriptive version number of the OpenSSL in use.
#define ossl_digest_fun(var, fun) \
-{ \
+do { \
int __kl; \
const EVP_MD *__md; \
\
if (!__md) { \
EVP_cleanup(); \
return -1; \
- } \
+ } \
\
__kl = fun(__md); \
\
#define ossl_cipher_fun(var, fun) \
-{ \
+do { \
int __kl; \
const EVP_CIPHER *__ciph; \
\
if (!__ciph) { \
EVP_cleanup(); \
return -1; \
- } \
+ } \
\
__kl = fun(__ciph); \
\
\f
/*
- *
+ *
* RAND
- *
+ *
*/
DEFUN("ossl-rand-bytes", Fossl_rand_bytes, 1, 1, 0, /*
Return COUNT bytes of randomness.
EVP_MD_CTX *mdctx;
const EVP_MD *md;
unsigned char md_value[EVP_MAX_MD_SIZE];
- unsigned int md_len, md_blocksize, n;
+ unsigned int md_len, md_blocksize;
+ ssize_t n;
/* input file */
FILE *fp;
file = Fexpand_file_name(file, Qnil);
if (((fp = fopen((char *)XSTRING_DATA(file),"rb")) == NULL) ||
- (fseek(fp, 0, SEEK_SET)))
+ (fseek(fp, 0, SEEK_SET))) {
+ if (fp)
+ fclose(fp);
return wrong_type_argument(Qfile_readable_p, file);
-
+ }
OpenSSL_add_all_digests();
md = EVP_get_digestbyname(
if (!md) {
EVP_cleanup();
+ fclose(fp);
error ("no such digest");
}
mdctx = xnew(EVP_MD_CTX);
EVP_MD_CTX_init(mdctx);
md_blocksize = (unsigned int)(EVP_MD_block_size(md) / 8);
+ SXE_SET_UNUSED(md_blocksize);
EVP_DigestInit_ex(mdctx, md, NULL);
return Qnil;
}
EVP_DigestUpdate(mdctx, md_value, n);
- } while (n > 0);
+ } while (n > 0);
EVP_DigestFinal_ex(mdctx, md_value, &md_len);
EVP_MD_CTX_cleanup(mdctx);
}
-/*
+/*
*
* HMAC (aka keyed hashes)
- *
+ *
*/
DEFUN("ossl-hmac", Fossl_hmac, 3, 3, 0, /*
Return the message authentication code of MSG
/* buffer for the ciphertext */
unsigned char outbuf[EVP_MAX_MD_SIZE];
- unsigned int outlen, n;
+ unsigned int outlen;
+ ssize_t n;
/* buffer for external password */
char *password_ext;
unsigned int password_len;
file = Fexpand_file_name(file, Qnil);
if (((fp = fopen((char *)XSTRING_DATA(file),"rb")) == NULL) ||
- (fseek(fp, 0, SEEK_SET)))
+ (fseek(fp, 0, SEEK_SET))) {
+ if (fp)
+ fclose(fp);
return wrong_type_argument(Qfile_readable_p, file);
+ }
OpenSSL_add_all_digests();
return Qnil;
}
HMAC_Update(hmacctx, outbuf, n);
- } while (n > 0);
+ } while (n > 0);
HMAC_Final(hmacctx, outbuf, &outlen);
HMAC_CTX_cleanup(hmacctx);
xfree(hmacctx);
EVP_cleanup();
+ fclose(fp);
return make_ext_string((char*)outbuf, outlen, OSSL_CODING);
}
-/*
- *
+/*
+ *
* SYMMETRIC CIPHER
- *
+ *
*/
DEFUN("ossl-bytes-to-key", Fossl_bytes_to_key, 5, 5, 0, /*
Derive a key and initialisation vector (iv) suitable for a cipher.
COUNT \(a positive integer\) is the iteration count to use. This
indicates how often the hash algorithm is called recursively.
-Note: You probably want to put a wrapping encoder function
+Note: You probably want to put a wrapping encoder function
\(like `base16-encode-string'\) around it, since this returns
binary string data.
*/
STRING is the text to be encrypted.
-KEY should be a key generated suitably for this cipher, for example
+KEY should be a key generated suitably for this cipher, for example
by `ossl-bytes-to-key'.
Optional fourth argument IV should be an initialisation vector
{
/* buffer for the external string */
unsigned char string_in[1024];
- unsigned int string_len;
+ ssize_t string_len;
unsigned int block_len;
unsigned long file_size;
/* buffer for the ciphertext */
file = Fexpand_file_name(file, Qnil);
if (((fp = fopen((char *)XSTRING_DATA(file),"rb")) == NULL) ||
- (fseek(fp, 0, SEEK_SET)))
+ (fseek(fp, 0, SEEK_SET))) {
+ if (fp)
+ fclose(fp);
+ if (of)
+ fclose(of);
return wrong_type_argument(Qfile_readable_p, file);
+ }
fseek(fp, 0, SEEK_END);
- file_size = ftell(fp);
+ file_size = ftell(fp);
fseek(fp, 0, SEEK_SET);
if (!ciph) {
EVP_cleanup();
+ fclose(fp);
+ if (of)
+ fclose(of);
error ("no such cipher");
}
(unsigned char *)key_ext,
(unsigned char *)iv_ext)) {
EVP_cleanup();
+ fclose(fp);
+ if (of)
+ fclose(of);
xfree(ciphctx);
error("error in EncryptInit");
}
if (string_len < 0) {
EVP_cleanup();
fclose(fp);
+ if (of)
+ fclose(of);
xfree(ciphctx);
error("file corrupted");
return Qnil;
obp, &tmplen,
string_in, string_len)) {
EVP_cleanup();
+ fclose(fp);
+ if (of)
+ fclose(of);
xfree(ciphctx);
error("error in EncryptUpdate");
}
*/
if (!EVP_EncryptFinal(ciphctx, obp, &tmplen)) {
EVP_cleanup();
+ fclose(fp);
+ if (of)
+ fclose(of);
xfree(ciphctx);
error("error in EncryptFinal");
}
C_STRING_ALLOCA, string_ext, OSSL_CODING);
string_len = OSSL_STRING_LENGTH(string);
- if (!string_len)
+ if (!string_len)
error ("string must be of non-zero positive length.");
OpenSSL_add_all_algorithms();
{
/* buffer for the external string */
unsigned char string_in[1024];
- unsigned int string_len;
+ ssize_t string_len;
unsigned int block_len;
unsigned long file_size;
/* buffer for the deciphered text */
file = Fexpand_file_name(file, Qnil);
if (((fp = fopen((char *)XSTRING_DATA(file),"rb")) == NULL) ||
- (fseek(fp, 0, SEEK_SET)))
+ (fseek(fp, 0, SEEK_SET))) {
+ if (fp)
+ fclose(fp);
+ if (of)
+ fclose(of);
return wrong_type_argument(Qfile_readable_p, file);
+ }
fseek(fp, 0, SEEK_END);
- file_size = ftell(fp);
+ file_size = ftell(fp);
fseek(fp, 0, SEEK_SET);
if (!ciph) {
EVP_cleanup();
+ fclose(fp);
+ if (of)
+ fclose(of);
error ("no such cipher");
}
(unsigned char *)key_ext,
(unsigned char *)iv_ext)) {
EVP_cleanup();
+ fclose(fp);
+ if (of)
+ fclose(of);
xfree(ciphctx);
error ("error in DecryptInit");
}
if (string_len < 0) {
EVP_cleanup();
fclose(fp);
+ if (of)
+ fclose(of);
xfree(ciphctx);
error("file corrupted");
return Qnil;
obp, &tmplen,
string_in, string_len)) {
EVP_cleanup();
+ fclose(fp);
+ if (of)
+ fclose(of);
xfree(ciphctx);
error ("error in DecryptUpdate");
}
*/
if (!EVP_DecryptFinal(ciphctx, obp, &tmplen)) {
EVP_cleanup();
+ fclose(fp);
+ if (of)
+ fclose(of);
xfree(ciphctx);
error ("error in DecryptFinal");
}
}
-/*
- *
+/*
+ *
* ASYMMETRIC CIPHER
- *
+ *
*/
/* This is an opaque object for storing PKEYs in lisp */
Lisp_Object Qevp_pkeyp;
static void
print_evp_pkey(Lisp_Object obj, Lisp_Object printcharfun, int escapeflag)
{
- char buf[256];
EVP_PKEY *pkey;
X509 *x509;
if (x509) {
X509_NAME *iss = X509_get_issuer_name(x509);
X509_NAME *sub = X509_get_subject_name(x509);
- write_c_string(" X509 Certificate", printcharfun);
+ write_c_string(" X509 Certificate", printcharfun);
write_c_string(" iss:", printcharfun);
write_c_string(X509_NAME_oneline(sub, NULL, 0), printcharfun);
write_c_string(" sub:", printcharfun);
write_c_string(";", printcharfun);
if (rsa_pkey_p(pkey))
- write_c_string(" RSA", printcharfun);
+ write_c_string(" RSA", printcharfun);
else if (dsa_pkey_p(pkey))
- write_c_string(" DSA", printcharfun);
+ write_c_string(" DSA", printcharfun);
else if (ec_pkey_p(pkey))
- write_c_string(" EC", printcharfun);
+ write_c_string(" EC", printcharfun);
if (ossl_pkey_has_private_data(pkey))
- write_c_string(" private/public key", printcharfun);
+ write_c_string(" private/public key", printcharfun);
else if (ossl_pkey_has_public_data(pkey))
- write_c_string(" public key", printcharfun);
+ write_c_string(" public key", printcharfun);
else
- write_c_string(" empty key", printcharfun);
+ write_c_string(" empty key", printcharfun);
if (EVP_PKEY_size(pkey) > 0) {
- snprintf(buf, 256, ", size %d", EVP_PKEY_size(pkey)*8);
- write_c_string(buf, printcharfun);
+ write_fmt_str(printcharfun, ", size %d", EVP_PKEY_size(pkey)*8);
}
}
- write_c_string(">", printcharfun);
+ write_c_string(">", printcharfun);
/* avoid some warning */
if (escapeflag);
}
DEFUN("ossl-pkey-size", Fossl_pkey_size, 1, 1, 0, /*
-Return the size a public key PKEY in bits.
+Return the size a public key PKEY in bits.
*/
(pkey))
{
error ("pkey1 must be of RSA type");
if (!rsa_pkey_p(pk2))
error ("pkey2 must be of RSA type");
-
+
rk1 = (pk1->pkey).rsa;
rk2 = (pk2->pkey).rsa;
error ("pkey1 must be of DSA type");
if (!dsa_pkey_p(pk2))
error ("pkey2 must be of DSA type");
-
+
dk1 = (pk1->pkey).dsa;
dk2 = (pk2->pkey).dsa;
(curve))
{
EVP_PKEY *pkey;
- EC_KEY *eckey = EC_KEY_new();
+ EC_KEY *eckey;
CHECK_SYMBOL(curve);
eckey = EC_KEY_new_by_curve_name(
ec_curve_by_name((char *)string_data(XSYMBOL(curve)->name)));
- if ((eckey == NULL)) {
+ if (eckey == NULL) {
error ("no such curve");
}
Return an envelope derived from encrypting STRING by CIPHER under PKEY
with the hybrid technique.
-That is, create a random key/iv pair for the symmetric encryption with
+That is, create a random key/iv pair for the symmetric encryption with
CIPHER and encrypt that key/iv asymmetrically with the provided public
key.
-The envelope returned is a list
+The envelope returned is a list
\(encrypted_string encrypted_key encrypted_iv\)
where
`encrypted_string' is the (symmetrically) encrypted message
encrypt the result with the private key PKEY.
Note: Due to some relationship between the public key system and the
-message digest you cannot use every digest algorithm with every
+message digest you cannot use every digest algorithm with every
private key type.
The most certain results will be achieved using
RSA keys with RSA-* digests, DSA keys with DSA-* digests.
pk = XEVPPKEY(pkey)->evp_pkey;
pk509 = XEVPPKEY(pkey)->x509;
+ SXE_SET_UNUSED(pk509);
if ((fp = fopen((char *)XSTRING_DATA(file), "w")) == NULL)
error ("error opening file.");
pk = XEVPPKEY(pkey)->evp_pkey;
pk509 = XEVPPKEY(pkey)->x509;
+ SXE_SET_UNUSED(pk509);
if (!ossl_pkey_has_private_data(pk))
return Fossl_pem_write_public_key(file, pkey);
CHECK_SYMBOL(cipher);
OpenSSL_add_all_algorithms();
-
+
if (NILP(cipher)) {
ciph = NULL;
pass = NULL;
EVP_PKEY *pk;
Lisp_Object result;
/* bio stuff */
- BIO *b;
+ BIO *b;
/* gc stuff */
struct gcpro gcpro1;
if (!(b = BIO_new(BIO_s_null()))) {
UNGCPRO;
error("cannot open memory buffer");
- return Qnil;
+ return Qnil;
}
result = build_string("");
const EVP_CIPHER *ciph;
char *pass;
/* bio stuff */
- BIO *b;
+ BIO *b;
struct gcpro gcpro1, gcpro2, gcpro3;
GCPRO3(pkey, cipher, password);
CHECK_SYMBOL(cipher);
OpenSSL_add_all_algorithms();
-
+
if (NILP(cipher)) {
ciph = NULL;
pass = NULL;
if (!(b = BIO_new(BIO_s_null()))) {
UNGCPRO;
error("cannot open memory buffer");
- return Qnil;
+ return Qnil;
}
result = build_string("");
parent = XSSLCONN(obj)->parent;
write_c_string("#<OpenSSL socket layer: ", printcharfun);
- if (conn == NULL)
+ if (conn == NULL)
write_c_string("dead", printcharfun);
else
write_c_string(SSL_get_version(conn), printcharfun);
/* Advanced step-by-step initialisation */
#define OSSL_CHECK_PROCESS(process) \
-{ \
+do { \
/* Make sure the process is really alive. */ \
if (!EQ(XPROCESS(process)->status_symbol, Qrun)) \
error("Network stream %s not alive", \
static Lisp_Object
ossl_ssl_prepare_cmeth(Lisp_Object method)
{
- SSL_METHOD *meth = NULL;
+ SSL_METHOD *meth = NULL;
Lisp_SSL_CONN *lisp_ssl_conn;
/* start preparing the conn object */
SSL_library_init();
SSL_load_error_strings();
- if (0);
- else if (EQ(method, Qssl2))
+ /* I would love to make 'meth' const SSL_METHOD* as well as the
+ 'ssl_meth' member of 'Lisp_SSL_CONN' unfortunately not all
+ supported versions of OpenSSL then take const SSL_METHOD*
+ as arguments, so turning off the cast qualifier warning and
+ store non-const is a more reasonable solution.
+ */
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wcast-qual"
+ if (0) {
+ } else if (EQ(method, Qssl2)) {
+#if HAVE_SSLV2_CLIENT_METHOD
meth = (SSL_METHOD *)SSLv2_client_method();
- else if (EQ(method, Qssl3))
+#else
+ error("sslv2 client method not supported");
+#endif
+ } else if (EQ(method, Qssl3)) {
+#if HAVE_SSLV3_CLIENT_METHOD
meth = (SSL_METHOD *)SSLv3_client_method();
- else if (EQ(method, Qssl23))
+#else
+ error("sslv3 client method not supported");
+#endif
+ } else if (EQ(method, Qssl23)) {
+#if HAVE_SSLV23_CLIENT_METHOD
meth = (SSL_METHOD *)SSLv23_client_method();
- else if (EQ(method, Qtls1))
+#else
+ error("sslv23 client method not supported");
+#endif
+ } else if (EQ(method, Qtls1)) {
+#if HAVE_TLSV1_CLIENT_METHOD
meth = (SSL_METHOD *)TLSv1_client_method();
- else
+#else
+ error("tlsv1 client method not supported");
+#endif
+ } else {
+#if HAVE_TLSV1_CLIENT_METHOD
meth = (SSL_METHOD *)TLSv1_client_method();
-
+#else
+ error("default tlsv1 client method not supported");
+#endif
+ }
+#pragma GCC diagnostic pop
if (!RAND_status())
error("OSSL: not enough random data");
SSL_library_init();
SSL_load_error_strings();
- if (0);
- else if (EQ(method, Qssl2))
+ /* I would love to make 'meth' const SSL_METHOD* as well as the
+ 'ssl_meth' member of 'Lisp_SSL_CONN' unfortunately not all
+ supported versions of OpenSSL then take const SSL_METHOD*
+ as arguments, so turning off the cast qualifier warning and
+ store non-const is a more reasonable solution.
+ */
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wcast-qual"
+ if (0) {
+ } else if (EQ(method, Qssl2)) {
+#if HAVE_SSLV2_SERVER_METHOD
meth = (SSL_METHOD *)SSLv2_server_method();
- else if (EQ(method, Qssl3))
+#else
+ error("sslv2 client method not supported");
+#endif
+ } else if (EQ(method, Qssl3)) {
+#if HAVE_SSLV3_SERVER_METHOD
meth = (SSL_METHOD *)SSLv3_server_method();
- else if (EQ(method, Qssl23))
+#else
+ error("sslv3 client method not supported");
+#endif
+ } else if (EQ(method, Qssl23)) {
+#if HAVE_SSLV23_SERVER_METHOD
meth = (SSL_METHOD *)SSLv23_server_method();
- else if (EQ(method, Qtls1))
+#else
+ error("sslv23 client method not supported");
+#endif
+ } else if (EQ(method, Qtls1)) {
+#if HAVE_TLSV1_SERVER_METHOD
meth = (SSL_METHOD *)TLSv1_server_method();
- else
+#else
+ error("tlsv1 client method not supported");
+#endif
+ } else {
+#if HAVE_SSLV23_SERVER_METHOD
meth = (SSL_METHOD *)SSLv23_server_method();
-
+#else
+ error("default sslv23 client method not supported");
+#endif
+ }
+#pragma GCC diagnostic pop
if (!RAND_status())
error("OSSL: not enough random data");
if (fun && fun(ssl_conn, ca) &&
(conn = XSSLCONN(ssl_conn)->ssl_conn)) {
+#if HAVE_SSL_VERIFY_CERT_CHAIN
ssl_verify_cert_chain(conn, SSL_get_peer_cert_chain(conn));
+#else
+ error("SSL certificate chain verification not supported");
+#endif
UNGCPRO;
return Qt;
}
error("SSL connection dead");
conn = XSSLCONN(ssl_conn)->ssl_conn;
+ SXE_SET_UNUSED(conn);
+
process = XSSLCONN(ssl_conn)->parent;
/* Make sure the process is really alive. */
/* store the original process filter */
proc_filter = XPROCESS(process)->filter;
+ SXE_SET_UNUSED(proc_filter);
ret = Lstream_write(out, XSTRING_DATA(string), XSTRING_LENGTH(string));
Lstream_flush(out);
CHECK_SSLCONN(ssl_conn);
- conn = XSSLCONN(ssl_conn)->ssl_conn;
+ conn = XSSLCONN(ssl_conn)->ssl_conn;
vrc = SSL_get_verify_result(conn);
result = Fcons(
{
/* SSL connection stuff */
SSL *conn=NULL;
- SSL_CIPHER *ciph;
+ const SSL_CIPHER *ciph;
/* network stream stuff */
Lisp_SSL_CONN *lisp_ssl_conn;
{
/* SSL connection stuff */
SSL *conn=NULL;
- SSL_CIPHER *ciph;
+ const SSL_CIPHER *ciph;
/* network stream stuff */
Lisp_SSL_CONN *lisp_ssl_conn;
{
/* SSL connection stuff */
SSL *conn=NULL;
- SSL_CIPHER *ciph;
+ const SSL_CIPHER *ciph;
int alg_bits, strength_bits;
/* network stream stuff */
Lisp_SSL_CONN *lisp_ssl_conn;
{
/* SSL connection stuff */
SSL *conn=NULL;
- SSL_CIPHER *ciph;
+ const SSL_CIPHER *ciph;
/* network stream stuff */
Lisp_SSL_CONN *lisp_ssl_conn;