Vulnerability: An issue was discovered in the pam_p11 component 0.2.0 and 0.3.0 for OpenSC. If a smart card creates a signature with a length longer than 256 bytes, this triggers a buffer overflow. This may be the case for RSA keys with 4096 bits depending on the signature scheme.
Vulnerability ID: CVE-2019-16058
CWE: CWE-119
Severity score: 2.9
Project: https://github.com/OpenSC/pam_p11
Published: 2019-09-06
File: src/pam_p11.c
Commit message: Use EVP_PKEY_size() to allocate correct size of signature buffer. (#18)

Do not use fixed buffer size for signature, EVP_SignFinal() requires
buffer for signature at least  EVP_PKEY_size(pkey) bytes in size.

Fixes crash when using 4K RSA signatures (https://github.com/OpenSC/pam_p11/issues/16, https://github.com/OpenSC/pam_p11/issues/15)
Commit author: Peter Popovec

Vulnerable version (before fix):
 #include <openssl/crypto.h> #include <libp11.h> #include <regex.h>  /* openssl deprecated API emulation */ #ifndef HAVE_EVP_MD_CTX_NEW static int key_verify(pam_handle_t *pamh, int flags, PKCS11_KEY *authkey) { 	int ok = 0; 	unsigned char challenge[30]; 	unsigned char signature[256]; 	unsigned int siglen = sizeof signature; 	const EVP_MD *md = EVP_sha1(); 	EVP_MD_CTX *md_ctx = EVP_MD_CTX_new(); 	EVP_PKEY *privkey = PKCS11_get_private_key(authkey); 	EVP_PKEY *pubkey = PKCS11_get_public_key(authkey);  	/* Verify a SHA-1 hash of random data, signed by the key. 	 * 	 * Note that this will not work keys that aren't eligible for signing. static int key_verify(pam_handle_t *pamh, int flags, PKCS11_KEY *authkey) 	ok = 1;  err: 	if (NULL != pubkey) 		EVP_PKEY_free(pubkey); 	if (NULL != privkey)

Fixed version (after fix):
 #include <openssl/crypto.h> #include <libp11.h> #include <regex.h> #include <stdlib.h>  /* openssl deprecated API emulation */ #ifndef HAVE_EVP_MD_CTX_NEW static int key_verify(pam_handle_t *pamh, int flags, PKCS11_KEY *authkey) { 	int ok = 0; 	unsigned char challenge[30]; 	unsigned char *signature = NULL; 	unsigned int siglen; 	const EVP_MD *md = EVP_sha1(); 	EVP_MD_CTX *md_ctx = EVP_MD_CTX_new(); 	EVP_PKEY *privkey = PKCS11_get_private_key(authkey); 	EVP_PKEY *pubkey = PKCS11_get_public_key(authkey);  	if (NULL == privkey) 		goto err; 	siglen = EVP_PKEY_size(privkey); 	if (siglen <= 0) 		goto err; 	signature = malloc(siglen); 	if (NULL == signature) 		goto err;  	/* Verify a SHA-1 hash of random data, signed by the key. 	 * 	 * Note that this will not work keys that aren't eligible for signing. static int key_verify(pam_handle_t *pamh, int flags, PKCS11_KEY *authkey) 	ok = 1;  err: 	free(signature); 	if (NULL != pubkey) 		EVP_PKEY_free(pubkey); 	if (NULL != privkey)

Patch:
patch: @@ -31,6 +31,7 @@
 #include <openssl/crypto.h>
 #include <libp11.h>
 #include <regex.h>
+#include <stdlib.h>
 
 /* openssl deprecated API emulation */
 #ifndef HAVE_EVP_MD_CTX_NEW
@@ -634,13 +635,22 @@ static int key_verify(pam_handle_t *pamh, int flags, PKCS11_KEY *authkey)
 {
 	int ok = 0;
 	unsigned char challenge[30];
-	unsigned char signature[256];
-	unsigned int siglen = sizeof signature;
+	unsigned char *signature = NULL;
+	unsigned int siglen;
 	const EVP_MD *md = EVP_sha1();
 	EVP_MD_CTX *md_ctx = EVP_MD_CTX_new();
 	EVP_PKEY *privkey = PKCS11_get_private_key(authkey);
 	EVP_PKEY *pubkey = PKCS11_get_public_key(authkey);
 
+	if (NULL == privkey)
+		goto err;
+	siglen = EVP_PKEY_size(privkey);
+	if (siglen <= 0)
+		goto err;
+	signature = malloc(siglen);
+	if (NULL == signature)
+		goto err;
+
 	/* Verify a SHA-1 hash of random data, signed by the key.
 	 *
 	 * Note that this will not work keys that aren't eligible for signing.
@@ -667,6 +677,7 @@ static int key_verify(pam_handle_t *pamh, int flags, PKCS11_KEY *authkey)
 	ok = 1;
 
 err:
+	free(signature);
 	if (NULL != pubkey)
 		EVP_PKEY_free(pubkey);
 	if (NULL != privkey)
path: src/pam_p11.c