summaryrefslogtreecommitdiff
blob: 8cee3fb3f058b8ef0cb9ed47d36b73df7e2c1750 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
3 year old upstream proposal https://www.opensc-project.org/opensc/ticket/350

The fixed buffers allocated in pkcs11_init_cert are too small to hold the
output data for some certificates. It causes a "Buffer too small" error
to be returned from pkcs11_getattr_var.

Fix from Chromium OS:
Use heap instead of stack for variable length data when reading
certificate attributes.

Patch by Paul Stewart <pstew@chromium.org>

--- a/src/libp11-int.h
+++ b/src/libp11-int.h
@@ -136,6 +136,8 @@
 			      unsigned int, void *, size_t *);
 extern int pkcs11_getattr_bn(PKCS11_TOKEN *, CK_OBJECT_HANDLE,
 			     unsigned int, BIGNUM **);
+extern void *pkcs11_getattr_alloc(PKCS11_TOKEN *, CK_OBJECT_HANDLE,
+				  unsigned int, size_t *);
 
 #define key_getattr(key, t, p, s) \
 	pkcs11_getattr(KEY2TOKEN((key)), PRIVKEY((key))->object, (t), (p), (s))
--- a/src/p11_attr.c
+++ b/src/p11_attr.c
@@ -98,6 +98,32 @@
 	return *bn ? 0 : -1;
 }
 
+void *
+pkcs11_getattr_alloc(PKCS11_TOKEN * token, CK_OBJECT_HANDLE object,
+		     unsigned int type, size_t *size_out)
+{
+	size_t size = 0;
+	void *data = NULL;
+
+	if (pkcs11_getattr_var(token, object, type, NULL, &size))
+		return NULL;
+
+	data = malloc(size);
+	if (data == NULL)
+		return NULL;
+
+	memset(data, 0, size);
+	if (pkcs11_getattr_var(token, object, type, data, &size)) {
+		free(data);
+		return NULL;
+	}
+
+	if (size_out != NULL)
+		*size_out = size;
+
+	return data;
+}
+
 /*
  * Add attributes to template
  */
--- a/src/p11_cert.c
+++ b/src/p11_cert.c
@@ -136,10 +136,9 @@
 	PKCS11_TOKEN_private *tpriv;
 	PKCS11_CERT_private *kpriv;
 	PKCS11_CERT *cert, *tmp;
-	char label[256], data[2048];
-	unsigned char id[256];
 	CK_CERTIFICATE_TYPE cert_type;
 	size_t size;
+	void *data;
 
 	size = sizeof(cert_type);
 	if (pkcs11_getattr_var(token, obj, CKA_CERTIFICATE_TYPE, &cert_type, &size))
@@ -165,18 +164,32 @@
 	kpriv->object = obj;
 	kpriv->parent = token;
 
-	if (!pkcs11_getattr_s(token, obj, CKA_LABEL, label, sizeof(label)))
-		cert->label = BUF_strdup(label);
-	size = sizeof(data);
-	if (!pkcs11_getattr_var(token, obj, CKA_VALUE, data, &size)) {
-		const unsigned char *p = (unsigned char *) data;
+	data = pkcs11_getattr_alloc(token, obj, CKA_LABEL, &size);
+	if (data != NULL) {
+		char *label = data;
+		/* Fix any null-termination issues with the label */
+		if (label[size - 1] != '\0') {
+			label = realloc(label, size + 1);
+			if (label == NULL) {
+				free(data);
+				return -1;
+			}
+			label[size] = '\0';
+		}
+		cert->label = label;
+	}
 
+	data = pkcs11_getattr_alloc(token, obj, CKA_VALUE, &size);
+	if (data != NULL) {
+		const unsigned char *p = data;
 		cert->x509 = d2i_X509(NULL, &p, size);
+		free(data);
 	}
-	cert->id_len = sizeof(id);
-	if (!pkcs11_getattr_var(token, obj, CKA_ID, id, &cert->id_len)) {
-		cert->id = (unsigned char *) malloc(cert->id_len);
-		memcpy(cert->id, id, cert->id_len);
+	data = pkcs11_getattr_alloc(token, obj, CKA_ID, &cert->id_len);
+	if (data != NULL) {
+		cert->id = data;
+	} else {
+		cert->id_len = 0;
 	}
 
 	/* Initialize internal information */