Change-Id: I9ebd4c2421e467afc2a153bd8f28d1af26524ca0
Reviewed-on: http://photon-jenkins.eng.vmware.com:8082/6440
Tested-by: gerrit-photon <photon-checkins@vmware.com>
Reviewed-by: Anish Swaminathan <anishs@vmware.com>
| 1 | 1 |
new file mode 100644 |
| ... | ... |
@@ -0,0 +1,323 @@ |
| 0 |
+From 511563ce763b1e98e3fb3b3e3addfef550ff99b2 Mon Sep 17 00:00:00 2001 |
|
| 1 |
+From: Tobias Brunner <tobias@strongswan.org> |
|
| 2 |
+Date: Tue, 28 Aug 2018 11:26:24 +0200 |
|
| 3 |
+Subject: [PATCH] gmp: Don't parse PKCS1 v1.5 RSA signatures to verify them |
|
| 4 |
+ |
|
| 5 |
+Instead we generate the expected signature encoding and compare it to the |
|
| 6 |
+decrypted value. |
|
| 7 |
+ |
|
| 8 |
+Due to the lenient nature of the previous parsing code (minimum padding |
|
| 9 |
+length was not enforced, the algorithmIdentifier/OID parser accepts arbitrary |
|
| 10 |
+data after OIDs and in the parameters field etc.) it was susceptible to |
|
| 11 |
+Daniel Bleichenbacher's low-exponent attack (from 2006!), which allowed |
|
| 12 |
+forging signatures for keys that use low public exponents (i.e. e=3). |
|
| 13 |
+ |
|
| 14 |
+Since the public exponent is usually set to 0x10001 (65537) since quite a |
|
| 15 |
+while, the flaws in the previous code should not have had that much of a |
|
| 16 |
+practical impact in recent years. |
|
| 17 |
+ |
|
| 18 |
+Fixes: CVE-2018-16151, CVE-2018-16152 |
|
| 19 |
+--- |
|
| 20 |
+ .../plugins/gmp/gmp_rsa_private_key.c | 66 +++++---- |
|
| 21 |
+ src/libstrongswan/plugins/gmp/gmp_rsa_public_key.c | 156 ++------------------- |
|
| 22 |
+ 2 files changed, 52 insertions(+), 170 deletions(-) |
|
| 23 |
+ |
|
| 24 |
+diff --git a/src/libstrongswan/plugins/gmp/gmp_rsa_private_key.c b/src/libstrongswan/plugins/gmp/gmp_rsa_private_key.c |
|
| 25 |
+index 241ef7d3b12b..edc178e96a4f 100644 |
|
| 26 |
+--- a/src/libstrongswan/plugins/gmp/gmp_rsa_private_key.c |
|
| 27 |
+@@ -264,14 +264,15 @@ static chunk_t rsasp1(private_gmp_rsa_private_key_t *this, chunk_t data) |
|
| 28 |
+ } |
|
| 29 |
+ |
|
| 30 |
+ /** |
|
| 31 |
+- * Build a signature using the PKCS#1 EMSA scheme |
|
| 32 |
++ * Hashes the data and builds the plaintext signature value with EMSA |
|
| 33 |
++ * PKCS#1 v1.5 padding. |
|
| 34 |
++ * |
|
| 35 |
++ * Allocates the signature data. |
|
| 36 |
+ */ |
|
| 37 |
+-static bool build_emsa_pkcs1_signature(private_gmp_rsa_private_key_t *this, |
|
| 38 |
+- hash_algorithm_t hash_algorithm, |
|
| 39 |
+- chunk_t data, chunk_t *signature) |
|
| 40 |
++bool gmp_emsa_pkcs1_signature_data(hash_algorithm_t hash_algorithm, |
|
| 41 |
++ chunk_t data, size_t keylen, chunk_t *em) |
|
| 42 |
+ {
|
|
| 43 |
+ chunk_t digestInfo = chunk_empty; |
|
| 44 |
+- chunk_t em; |
|
| 45 |
+ |
|
| 46 |
+ if (hash_algorithm != HASH_UNKNOWN) |
|
| 47 |
+ {
|
|
| 48 |
+@@ -295,43 +296,56 @@ static bool build_emsa_pkcs1_signature(private_gmp_rsa_private_key_t *this, |
|
| 49 |
+ /* build DER-encoded digestInfo */ |
|
| 50 |
+ digestInfo = asn1_wrap(ASN1_SEQUENCE, "mm", |
|
| 51 |
+ asn1_algorithmIdentifier(hash_oid), |
|
| 52 |
+- asn1_simple_object(ASN1_OCTET_STRING, hash) |
|
| 53 |
+- ); |
|
| 54 |
+- chunk_free(&hash); |
|
| 55 |
++ asn1_wrap(ASN1_OCTET_STRING, "m", hash)); |
|
| 56 |
++ |
|
| 57 |
+ data = digestInfo; |
|
| 58 |
+ } |
|
| 59 |
+ |
|
| 60 |
+- if (data.len > this->k - 3) |
|
| 61 |
++ if (data.len > keylen - 11) |
|
| 62 |
+ {
|
|
| 63 |
+- free(digestInfo.ptr); |
|
| 64 |
+- DBG1(DBG_LIB, "unable to sign %d bytes using a %dbit key", data.len, |
|
| 65 |
+- mpz_sizeinbase(this->n, 2)); |
|
| 66 |
++ chunk_free(&digestInfo); |
|
| 67 |
++ DBG1(DBG_LIB, "signature value of %zu bytes is too long for key of " |
|
| 68 |
++ "%zu bytes", data.len, keylen); |
|
| 69 |
+ return FALSE; |
|
| 70 |
+ } |
|
| 71 |
+ |
|
| 72 |
+- /* build chunk to rsa-decrypt: |
|
| 73 |
+- * EM = 0x00 || 0x01 || PS || 0x00 || T. |
|
| 74 |
+- * PS = 0xFF padding, with length to fill em |
|
| 75 |
++ /* EM = 0x00 || 0x01 || PS || 0x00 || T. |
|
| 76 |
++ * PS = 0xFF padding, with length to fill em (at least 8 bytes) |
|
| 77 |
+ * T = encoded_hash |
|
| 78 |
+ */ |
|
| 79 |
+- em.len = this->k; |
|
| 80 |
+- em.ptr = malloc(em.len); |
|
| 81 |
++ *em = chunk_alloc(keylen); |
|
| 82 |
+ |
|
| 83 |
+ /* fill em with padding */ |
|
| 84 |
+- memset(em.ptr, 0xFF, em.len); |
|
| 85 |
++ memset(em->ptr, 0xFF, em->len); |
|
| 86 |
+ /* set magic bytes */ |
|
| 87 |
+- *(em.ptr) = 0x00; |
|
| 88 |
+- *(em.ptr+1) = 0x01; |
|
| 89 |
+- *(em.ptr + em.len - data.len - 1) = 0x00; |
|
| 90 |
+- /* set DER-encoded hash */ |
|
| 91 |
+- memcpy(em.ptr + em.len - data.len, data.ptr, data.len); |
|
| 92 |
++ *(em->ptr) = 0x00; |
|
| 93 |
++ *(em->ptr+1) = 0x01; |
|
| 94 |
++ *(em->ptr + em->len - data.len - 1) = 0x00; |
|
| 95 |
++ /* set encoded hash */ |
|
| 96 |
++ memcpy(em->ptr + em->len - data.len, data.ptr, data.len); |
|
| 97 |
++ |
|
| 98 |
++ chunk_clear(&digestInfo); |
|
| 99 |
++ return TRUE; |
|
| 100 |
++} |
|
| 101 |
++ |
|
| 102 |
++/** |
|
| 103 |
++ * Build a signature using the PKCS#1 EMSA scheme |
|
| 104 |
++ */ |
|
| 105 |
++static bool build_emsa_pkcs1_signature(private_gmp_rsa_private_key_t *this, |
|
| 106 |
++ hash_algorithm_t hash_algorithm, |
|
| 107 |
++ chunk_t data, chunk_t *signature) |
|
| 108 |
++{
|
|
| 109 |
++ chunk_t em; |
|
| 110 |
++ |
|
| 111 |
++ if (!gmp_emsa_pkcs1_signature_data(hash_algorithm, data, this->k, &em)) |
|
| 112 |
++ {
|
|
| 113 |
++ return FALSE; |
|
| 114 |
++ } |
|
| 115 |
+ |
|
| 116 |
+ /* build signature */ |
|
| 117 |
+ *signature = rsasp1(this, em); |
|
| 118 |
+ |
|
| 119 |
+- free(digestInfo.ptr); |
|
| 120 |
+- free(em.ptr); |
|
| 121 |
+- |
|
| 122 |
++ chunk_free(&em); |
|
| 123 |
+ return TRUE; |
|
| 124 |
+ } |
|
| 125 |
+ |
|
| 126 |
+diff --git a/src/libstrongswan/plugins/gmp/gmp_rsa_public_key.c b/src/libstrongswan/plugins/gmp/gmp_rsa_public_key.c |
|
| 127 |
+index 52bc9fb38046..ce9a80fadf2a 100644 |
|
| 128 |
+--- a/src/libstrongswan/plugins/gmp/gmp_rsa_public_key.c |
|
| 129 |
+@@ -70,7 +70,9 @@ struct private_gmp_rsa_public_key_t {
|
|
| 130 |
+ /** |
|
| 131 |
+ * Shared functions defined in gmp_rsa_private_key.c |
|
| 132 |
+ */ |
|
| 133 |
+-extern chunk_t gmp_mpz_to_chunk(const mpz_t value); |
|
| 134 |
++chunk_t gmp_mpz_to_chunk(const mpz_t value); |
|
| 135 |
++bool gmp_emsa_pkcs1_signature_data(hash_algorithm_t hash_algorithm, |
|
| 136 |
++ chunk_t data, size_t keylen, chunk_t *em); |
|
| 137 |
+ |
|
| 138 |
+ /** |
|
| 139 |
+ * RSAEP algorithm specified in PKCS#1. |
|
| 140 |
+--- a/src/libstrongswan/plugins/gmp/gmp_rsa_public_key.c |
|
| 141 |
+@@ -115,26 +115,13 @@ |
|
| 142 |
+ } |
|
| 143 |
+ |
|
| 144 |
+ /** |
|
| 145 |
+- * ASN.1 definition of digestInfo |
|
| 146 |
+- */ |
|
| 147 |
+-static const asn1Object_t digestInfoObjects[] = {
|
|
| 148 |
+- { 0, "digestInfo", ASN1_SEQUENCE, ASN1_OBJ }, /* 0 */
|
|
| 149 |
+- { 1, "digestAlgorithm", ASN1_EOC, ASN1_RAW }, /* 1 */
|
|
| 150 |
+- { 1, "digest", ASN1_OCTET_STRING, ASN1_BODY }, /* 2 */
|
|
| 151 |
+- { 0, "exit", ASN1_EOC, ASN1_EXIT }
|
|
| 152 |
+-}; |
|
| 153 |
+-#define DIGEST_INFO 0 |
|
| 154 |
+-#define DIGEST_INFO_ALGORITHM 1 |
|
| 155 |
+-#define DIGEST_INFO_DIGEST 2 |
|
| 156 |
+- |
|
| 157 |
+-/** |
|
| 158 |
+ * Verification of an EMPSA PKCS1 signature described in PKCS#1 |
|
| 159 |
+ */ |
|
| 160 |
+ static bool verify_emsa_pkcs1_signature(private_gmp_rsa_public_key_t *this, |
|
| 161 |
+ hash_algorithm_t algorithm, |
|
| 162 |
+ chunk_t data, chunk_t signature) |
|
| 163 |
+ {
|
|
| 164 |
+- chunk_t em_ori, em; |
|
| 165 |
++ chunk_t em_expected, em; |
|
| 166 |
+ bool success = FALSE; |
|
| 167 |
+ |
|
| 168 |
+ /* remove any preceding 0-bytes from signature */ |
|
| 169 |
+@@ -148,140 +137,19 @@ static bool verify_emsa_pkcs1_signature(private_gmp_rsa_public_key_t *this, |
|
| 170 |
+ return FALSE; |
|
| 171 |
+ } |
|
| 172 |
+ |
|
| 173 |
+- /* unpack signature */ |
|
| 174 |
+- em_ori = em = rsavp1(this, signature); |
|
| 175 |
+- |
|
| 176 |
+- /* result should look like this: |
|
| 177 |
+- * EM = 0x00 || 0x01 || PS || 0x00 || T. |
|
| 178 |
+- * PS = 0xFF padding, with length to fill em |
|
| 179 |
+- * T = oid || hash |
|
| 180 |
+- */ |
|
| 181 |
+- |
|
| 182 |
+- /* check magic bytes */ |
|
| 183 |
+- if (em.len < 2 || *(em.ptr) != 0x00 || *(em.ptr+1) != 0x01) |
|
| 184 |
++ /* generate expected signature value */ |
|
| 185 |
++ if (!gmp_emsa_pkcs1_signature_data(algorithm, data, this->k, &em_expected)) |
|
| 186 |
+ {
|
|
| 187 |
+- goto end; |
|
| 188 |
+- } |
|
| 189 |
+- em = chunk_skip(em, 2); |
|
| 190 |
+- |
|
| 191 |
+- /* find magic 0x00 */ |
|
| 192 |
+- while (em.len > 0) |
|
| 193 |
+- {
|
|
| 194 |
+- if (*em.ptr == 0x00) |
|
| 195 |
+- {
|
|
| 196 |
+- /* found magic byte, stop */ |
|
| 197 |
+- em = chunk_skip(em, 1); |
|
| 198 |
+- break; |
|
| 199 |
+- } |
|
| 200 |
+- else if (*em.ptr != 0xFF) |
|
| 201 |
+- {
|
|
| 202 |
+- /* bad padding, decryption failed ?!*/ |
|
| 203 |
+- goto end; |
|
| 204 |
+- } |
|
| 205 |
+- em = chunk_skip(em, 1); |
|
| 206 |
+- } |
|
| 207 |
+- |
|
| 208 |
+- if (em.len == 0) |
|
| 209 |
+- {
|
|
| 210 |
+- /* no digestInfo found */ |
|
| 211 |
+- goto end; |
|
| 212 |
+- } |
|
| 213 |
+- |
|
| 214 |
+- if (algorithm == HASH_UNKNOWN) |
|
| 215 |
+- { /* IKEv1 signatures without digestInfo */
|
|
| 216 |
+- if (em.len != data.len) |
|
| 217 |
+- {
|
|
| 218 |
+- DBG1(DBG_LIB, "hash size in signature is %u bytes instead of" |
|
| 219 |
+- " %u bytes", em.len, data.len); |
|
| 220 |
+- goto end; |
|
| 221 |
+- } |
|
| 222 |
+- success = memeq_const(em.ptr, data.ptr, data.len); |
|
| 223 |
++ return FALSE; |
|
| 224 |
+ } |
|
| 225 |
+- else |
|
| 226 |
+- { /* IKEv2 and X.509 certificate signatures */
|
|
| 227 |
+- asn1_parser_t *parser; |
|
| 228 |
+- chunk_t object; |
|
| 229 |
+- int objectID; |
|
| 230 |
+- hash_algorithm_t hash_algorithm = HASH_UNKNOWN; |
|
| 231 |
+- |
|
| 232 |
+- DBG2(DBG_LIB, "signature verification:"); |
|
| 233 |
+- parser = asn1_parser_create(digestInfoObjects, em); |
|
| 234 |
+ |
|
| 235 |
+- while (parser->iterate(parser, &objectID, &object)) |
|
| 236 |
+- {
|
|
| 237 |
+- switch (objectID) |
|
| 238 |
+- {
|
|
| 239 |
+- case DIGEST_INFO: |
|
| 240 |
+- {
|
|
| 241 |
+- if (em.len > object.len) |
|
| 242 |
+- {
|
|
| 243 |
+- DBG1(DBG_LIB, "digestInfo field in signature is" |
|
| 244 |
+- " followed by %u surplus bytes", |
|
| 245 |
+- em.len - object.len); |
|
| 246 |
+- goto end_parser; |
|
| 247 |
+- } |
|
| 248 |
+- break; |
|
| 249 |
+- } |
|
| 250 |
+- case DIGEST_INFO_ALGORITHM: |
|
| 251 |
+- {
|
|
| 252 |
+- int hash_oid = asn1_parse_algorithmIdentifier(object, |
|
| 253 |
+- parser->get_level(parser)+1, NULL); |
|
| 254 |
+- |
|
| 255 |
+- hash_algorithm = hasher_algorithm_from_oid(hash_oid); |
|
| 256 |
+- if (hash_algorithm == HASH_UNKNOWN || hash_algorithm != algorithm) |
|
| 257 |
+- {
|
|
| 258 |
+- DBG1(DBG_LIB, "expected hash algorithm %N, but found" |
|
| 259 |
+- " %N (OID: %#B)", hash_algorithm_names, algorithm, |
|
| 260 |
+- hash_algorithm_names, hash_algorithm, &object); |
|
| 261 |
+- goto end_parser; |
|
| 262 |
+- } |
|
| 263 |
+- break; |
|
| 264 |
+- } |
|
| 265 |
+- case DIGEST_INFO_DIGEST: |
|
| 266 |
+- {
|
|
| 267 |
+- chunk_t hash; |
|
| 268 |
+- hasher_t *hasher; |
|
| 269 |
+- |
|
| 270 |
+- hasher = lib->crypto->create_hasher(lib->crypto, hash_algorithm); |
|
| 271 |
+- if (hasher == NULL) |
|
| 272 |
+- {
|
|
| 273 |
+- DBG1(DBG_LIB, "hash algorithm %N not supported", |
|
| 274 |
+- hash_algorithm_names, hash_algorithm); |
|
| 275 |
+- goto end_parser; |
|
| 276 |
+- } |
|
| 277 |
+- |
|
| 278 |
+- if (object.len != hasher->get_hash_size(hasher)) |
|
| 279 |
+- {
|
|
| 280 |
+- DBG1(DBG_LIB, "hash size in signature is %u bytes" |
|
| 281 |
+- " instead of %u bytes", object.len, |
|
| 282 |
+- hasher->get_hash_size(hasher)); |
|
| 283 |
+- hasher->destroy(hasher); |
|
| 284 |
+- goto end_parser; |
|
| 285 |
+- } |
|
| 286 |
+- |
|
| 287 |
+- /* build our own hash and compare */ |
|
| 288 |
+- if (!hasher->allocate_hash(hasher, data, &hash)) |
|
| 289 |
+- {
|
|
| 290 |
+- hasher->destroy(hasher); |
|
| 291 |
+- goto end_parser; |
|
| 292 |
+- } |
|
| 293 |
+- hasher->destroy(hasher); |
|
| 294 |
+- success = memeq_const(object.ptr, hash.ptr, hash.len); |
|
| 295 |
+- free(hash.ptr); |
|
| 296 |
+- break; |
|
| 297 |
+- } |
|
| 298 |
+- default: |
|
| 299 |
+- break; |
|
| 300 |
+- } |
|
| 301 |
+- } |
|
| 302 |
++ /* unpack signature */ |
|
| 303 |
++ em = rsavp1(this, signature); |
|
| 304 |
+ |
|
| 305 |
+-end_parser: |
|
| 306 |
+- success &= parser->success(parser); |
|
| 307 |
+- parser->destroy(parser); |
|
| 308 |
+- } |
|
| 309 |
++ success = chunk_equals_const(em_expected, em); |
|
| 310 |
+ |
|
| 311 |
+-end: |
|
| 312 |
+- free(em_ori.ptr); |
|
| 313 |
++ chunk_free(&em_expected); |
|
| 314 |
++ chunk_free(&em); |
|
| 315 |
+ return success; |
|
| 316 |
+ } |
|
| 317 |
+ |
|
| 318 |
+-- |
|
| 319 |
+2.7.4 |
| ... | ... |
@@ -1,7 +1,7 @@ |
| 1 | 1 |
Summary: The OpenSource IPsec-based VPN Solution |
| 2 | 2 |
Name: strongswan |
| 3 | 3 |
Version: 5.5.2 |
| 4 |
-Release: 3%{?dist}
|
|
| 4 |
+Release: 4%{?dist}
|
|
| 5 | 5 |
License: GPLv2+ |
| 6 | 6 |
URL: https://www.strongswan.org/ |
| 7 | 7 |
Group: System Environment/Security |
| ... | ... |
@@ -14,6 +14,7 @@ Patch1: strongswan-CVE-2017-9022.patch |
| 14 | 14 |
Patch2: strongswan-CVE-2017-9023.patch |
| 15 | 15 |
Patch3: strongswan-CVE-2018-5388.patch |
| 16 | 16 |
Patch4: strongswan-CVE-2018-10811.patch |
| 17 |
+Patch5: CVE-2018-16151-16152.patch |
|
| 17 | 18 |
BuildRequires: autoconf |
| 18 | 19 |
|
| 19 | 20 |
%description |
| ... | ... |
@@ -26,6 +27,7 @@ strongSwan is a complete IPsec implementation for Linux 2.6, 3.x, and 4.x kernel |
| 26 | 26 |
%patch2 -p1 |
| 27 | 27 |
%patch3 -p1 |
| 28 | 28 |
%patch4 -p1 |
| 29 |
+%patch5 -p1 |
|
| 29 | 30 |
|
| 30 | 31 |
%build |
| 31 | 32 |
./configure --prefix=%{_prefix} --sysconfdir=%{_sysconfdir}
|
| ... | ... |
@@ -58,6 +60,8 @@ rm -rf %{buildroot}/*
|
| 58 | 58 |
|
| 59 | 59 |
|
| 60 | 60 |
%changelog |
| 61 |
+* Thu Jan 03 2019 Keerthana K <keerthanak@vmware.com> 5.5.2-4 |
|
| 62 |
+- Fix for CVE-2018-16151 and CVE-2018-16152. |
|
| 61 | 63 |
* Thu Aug 16 2018 Tapas Kundu <tkundu@vmware.com> 5.5.2-3 |
| 62 | 64 |
- Applied patch for CVE-2018-10811 |
| 63 | 65 |
* Wed Jul 11 2018 Ajay Kaher <akaher@vmware.com> 5.5.2-2 |