Skip to content

Commit 937d24f

Browse files
committed
wo#7449 . test case for Bleichenbacher-style signature forgery
Special thanks to Sze Yiu Chau of Purdue University ([email protected]) who reported the issue, and made major contributions towards defining this test case.
1 parent 9eaa6c2 commit 937d24f

File tree

6 files changed

+218
-0
lines changed

6 files changed

+218
-0
lines changed

tests/unit/libopenswan/Makefile

+1
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ clean check:
2323
@${MAKE} -C lo04-verifypubkeys $@
2424
@${MAKE} -C lo05-datatot $@
2525
@${MAKE} -C lo06-verifybadsigs $@
26+
@${MAKE} -C lo07-bleichenbacher-attack $@
2627

2728

2829

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
.gdbinit
2+
OUTPUT
3+
bleichenbacher-attack
4+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
# OpenS/WAN testing makefile
2+
# Copyright (C) 2018 Bart Trojanowski <[email protected]>
3+
# Copyright (C) 2014 Michael Richardson <[email protected]>
4+
# Copyright (C) 2002 Michael Richardson <[email protected]>
5+
#
6+
# This program is free software; you can redistribute it and/or modify it
7+
# under the terms of the GNU General Public License as published by the
8+
# Free Software Foundation; either version 2 of the License, or (at your
9+
# option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
10+
#
11+
# This program is distributed in the hope that it will be useful, but
12+
# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
13+
# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14+
# for more details.
15+
16+
OPENSWANSRCDIR?=$(shell cd ../../../..; pwd)
17+
srcdir?=${OPENSWANSRCDIR}/tests/unit/libpluto/lp01-spdbtest
18+
include $(OPENSWANSRCDIR)/Makefile.inc
19+
20+
EXTRAFLAGS+=${USERCOMPILE} ${PORTINCLUDE}
21+
EXTRAFLAGS+=-I${OPENSWANSRCDIR}/programs/pluto
22+
EXTRAFLAGS+=-I${OPENSWANSRCDIR}/include/pluto
23+
EXTRAFLAGS+=-I${OPENSWANSRCDIR}/include
24+
25+
EXTRALIBS+=${LIBOSWLOG} ${LIBOPENSWAN} ${LIBOSWLOG} ${LIBOSWKEYS}
26+
EXTRALIBS+=${NSS_LIBS} ${FIPS_LIBS} ${LIBGMP} ${CRYPTOLIBS} ${LIBPLUTO}
27+
28+
EXTRAOBJS+=${OBJDIRTOP}/programs/pluto/ikev2_crypto.o
29+
EXTRAOBJS+=${OBJDIRTOP}/programs/pluto/ikev2_rsa.o
30+
EXTRAOBJS+=${OBJDIRTOP}/programs/pluto/keys.o
31+
EXTRAOBJS+=${OBJDIRTOP}/lib/libopenswan/oswconf.o
32+
33+
EXTRAFLAGS+=${NSS_FLAGS} ${FIPS_FLAGS}
34+
EXTRAFLAGS+=${NSS_HDRDIRS} ${FIPS_HDRDIRS}
35+
36+
TESTNUMBER=lo07-bleichenbacher-attack
37+
TESTNAME=bleichenbacher-attack
38+
UNITTESTARGS=
39+
40+
Q=$(if $V,,@)
41+
42+
check: ${TESTNAME}
43+
@mkdir -p OUTPUT
44+
${COREULIMIT} && ./${TESTNAME} ${UNITTESTARGS} >OUTPUT/${TESTNAME}.txt 2>&1
45+
diff OUTPUT/${TESTNAME}.txt output.txt
46+
@: recordresults lib-$testobj "$testexpect" "$stat" lib-$testobj false
47+
48+
.PHONY: ${TESTNAME}
49+
${TESTNAME}: ${TESTNAME}.c
50+
@echo CC ${TESTNAME}.c
51+
$Q${CC} -o ${TESTNAME} ${EXTRAFLAGS} ${TESTNAME}.c ${EXTRAOBJS} ${EXTRALIBS}
52+
@echo "file ${TESTNAME}" >.gdbinit
53+
@echo "set args "${UNITTESTARGS} >>.gdbinit
54+
55+
update:
56+
cp OUTPUT/${TESTNAME}.txt output.txt
57+
58+
59+
initiate:
60+
61+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
1+
#define DEBUG
2+
#include <stdlib.h>
3+
#include <stddef.h>
4+
#include <limits.h>
5+
#include "openswan.h"
6+
#include "openswan/passert.h"
7+
#include "constants.h"
8+
#include "oswalloc.h"
9+
#include "oswlog.h"
10+
#include "secrets.h"
11+
#include "mpzfuncs.h"
12+
#include "id.h"
13+
#include "pluto/keys.h"
14+
#include "hexdump.c"
15+
#include "defs.h"
16+
#include "state.h"
17+
#include "packet.h"
18+
19+
struct spd_route;
20+
struct payload_digest;
21+
#include "ikev2.h"
22+
23+
const char *progname;
24+
struct prng not_very_random;
25+
26+
void whack_log(int mess_no, const char *message, ...)
27+
{
28+
}
29+
30+
void exit_tool(int stat)
31+
{
32+
exit(stat);
33+
}
34+
35+
int attack(uint8_t low_exponent, size_t modulus_bit_len)
36+
{
37+
/* this would be our message digest */
38+
uint8_t helloworldSHA1Bytes[] = {
39+
0x2A, 0xAE, 0x6C, 0x35, 0xC9, 0x4F, 0xCF, 0xB4, 0x15, 0xDB,
40+
0xE9, 0x5F, 0x40, 0x8B, 0x9C, 0xE9, 0x1E, 0xE8, 0x46, 0xED
41+
};
42+
43+
uint8_t attackBytes[] = {
44+
/* fake signature for 1024-bit modulus */
45+
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
46+
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
47+
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
48+
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
49+
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
50+
0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4e, 0xe7, 0x01, 0x3b,
51+
0x05, 0xba, 0x96, 0x90, 0x7a, 0x1f, 0xd0, 0x34, 0x4e, 0x77, 0x75, 0xce, 0x9a, 0x6b, 0x9e, 0xbc,
52+
0xb8, 0x0e, 0x72, 0x18, 0x1b, 0x48, 0x5e, 0x24, 0x9b, 0x96, 0x52, 0x4e, 0xca, 0xcc, 0xb8, 0x55
53+
};
54+
55+
/* if the attk is successful, this should not matter */
56+
size_t modulus_byte_len = modulus_bit_len/8;
57+
uint8_t modulusBytes[modulus_byte_len];
58+
59+
/* choose any 128-byte (1024-bit) modulus */
60+
prng_bytes(&not_very_random, modulusBytes, modulus_byte_len);
61+
printf("modulusBytes[%lu]:\n", modulus_byte_len);
62+
hexdump(modulusBytes, 0, modulus_byte_len);
63+
64+
/* low-exponent ... let's say 3 */
65+
uint8_t pubExpBytes[] = {
66+
low_exponent
67+
};
68+
printf("pubExpBytes[%lu]:\n", sizeof(pubExpBytes));
69+
hexdump(pubExpBytes, 0, sizeof(pubExpBytes));
70+
71+
/* prepare the public key */
72+
struct pubkey pk;
73+
pk.u.rsa.k = sizeof(attackBytes);
74+
n_to_mpz(&(pk.u.rsa.e), pubExpBytes, sizeof(pubExpBytes));
75+
n_to_mpz(&(pk.u.rsa.n), modulusBytes, sizeof(modulusBytes));
76+
77+
/* prepare a place holder state */
78+
struct state st;
79+
memset(&st, 0, sizeof(struct state));
80+
81+
pb_stream sig_pbs;
82+
sig_pbs.cur = attackBytes;
83+
sig_pbs.roof = attackBytes+sizeof(attackBytes);
84+
err_t e = NULL;
85+
86+
e = try_RSA_signature_v2(
87+
helloworldSHA1Bytes, // const u_char hash_val[MAX_DIGEST_LEN]
88+
sizeof(helloworldSHA1Bytes), // size_t hash_len
89+
&sig_pbs, // const pb_stream *sig_pbs
90+
&pk, // struct pubkey *kr
91+
&st // struct state *st
92+
);
93+
94+
printf("try_RSA_signature_v2: %s\n",
95+
e ? e : "OK");
96+
97+
int rc = 0;
98+
if (e)
99+
rc = strtoul(e, NULL, 0);
100+
101+
/* we caught the attack, return success */
102+
if (rc && rc != ULONG_MAX)
103+
return 0;
104+
105+
printf("ERROR: try_RSA_signature_v2() was fooled by our attack!\n");
106+
return -1;
107+
}
108+
109+
extern void load_oswcrypto(void);
110+
111+
int main(int argc, char *argv[])
112+
{
113+
int rc;
114+
115+
load_oswcrypto();
116+
117+
progname = argv[0];
118+
119+
prng_init(&not_very_random, "01234567", 8);
120+
121+
rc = attack(3, 1024);
122+
123+
exit(rc);
124+
}
125+
126+
/*
127+
* Local Variables:
128+
* c-style: pluto
129+
* c-basic-offset: 4
130+
* End:
131+
*/
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
This unit test case reads an ipsec.secrets file to find an RSA key in it.
2+
It then uses the private key found within to sign something (pseudo-random),
3+
and then uses the public key to validate that the signature was sane.
4+
5+
As an side affect of doing this, the signatures are written to a file
6+
(in binary), which is used in lo04-verifypubkeys.
7+
The public keys can be extracted from the *.secrets file using showhostkey,
8+
using the "make update" target in the lo04-verifypubkeys test case.
9+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
modulusBytes[128]:
2+
0000: 91 d5 f3 1f 46 27 25 30 30 53 bb 5a f2 ae e3 50
3+
0010: 07 ce 4a 50 2e 7c 96 32 a1 50 6b 52 79 4a c4 a6
4+
0020: 48 5e ac fb 1e 17 d9 30 d3 3c 7c 90 9b da 9d 13
5+
0030: 76 f5 d9 c1 82 6f 05 b1 04 5b ee f2 f6 73 13 9d
6+
0040: 1a d8 76 eb 4a aa ea d8 8d 2d 1b c7 49 5a 10 9a
7+
0050: 63 22 ef 22 79 d5 3b 00 6b fa 3f 57 d1 e6 69 24
8+
0060: 3c b5 b4 04 d6 47 30 87 b1 de 7a 7f 9d bb 68 bc
9+
0070: f5 b0 e6 d6 3b 8d 68 50 bf b5 24 4c 37 7e fd ea
10+
pubExpBytes[1]:
11+
0000: 03 00 00 00
12+
try_RSA_signature_v2: 4invalid Padding String

0 commit comments

Comments
 (0)