File: cert.cc

package info (click to toggle)
golang-github-google-certificate-transparency 0.0~git20160709.0.0f6e3d1~ds1-3
  • links: PTS, VCS
  • area: main
  • in suites: bookworm, bullseye, buster
  • size: 5,676 kB
  • sloc: cpp: 35,278; python: 11,838; java: 1,911; sh: 1,885; makefile: 950; xml: 520; ansic: 225
file content (1552 lines) | stat: -rw-r--r-- 49,788 bytes parent folder | download
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
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
/* -*- indent-tabs-mode: nil -*- */
#include "log/cert.h"
#include "log/ct_extensions.h"
#include "merkletree/serial_hasher.h"
#include "util/openssl_util.h"  // For LOG_OPENSSL_ERRORS
#include "util/util.h"

#include <glog/logging.h>
#include <openssl/asn1.h>
#include <openssl/bio.h>
#include <openssl/crypto.h>
#include <openssl/err.h>
#include <openssl/evp.h>
#include <openssl/objects.h>
#include <openssl/pem.h>
#include <openssl/x509.h>
#include <openssl/x509v3.h>
#include <time.h>
#include <algorithm>
#include <memory>
#include <string>
#include <vector>

using std::move;
using std::string;
using std::to_string;
using std::unique_ptr;
using std::vector;
using util::ClearOpenSSLErrors;
using util::StatusOr;
using util::error::Code;


#if OPENSSL_VERSION_NUMBER < 0x10002000L || defined(OPENSSL_IS_BORINGSSL)
// Backport from 1.0.2-beta3.
static int i2d_re_X509_tbs(X509* x, unsigned char** pp) {
  x->cert_info->enc.modified = 1;
  return i2d_X509_CINF(x->cert_info, pp);
}
#endif

#if OPENSSL_VERSION_NUMBER < 0x10002000L
static int X509_get_signature_nid(const X509* x) {
  return OBJ_obj2nid(x->sig_alg->algorithm);
}
#endif


namespace {
#if defined(OPENSSL_IS_BORINGSSL)
// BoringSSL doesn't have DSA hooked up so to accept these certs we have
// to do the work ourselves. Can be called with a non DSA issuer key but will
// always return false in that case.
//
// cert is the certificate that is to be checked
// issuer_key is the public key of the certificate issuer (should be DSA)
// Returns true if the DSA signature was correctly verified or false if
// it did not or there was any error along the way.
StatusOr<bool> check_dsa_signature(const X509* cert,
                                   EVP_PKEY* issuer_key) {
  // Before we start rummaging about through pointers ensure everything we need
  // is present
  if (!cert || !issuer_key || !X509_get_cert_info(cert)) {
    return ::util::Status(Code::FAILED_PRECONDITION,
                          "cert is null or missing cert_info");
  }

  X509_CINF* cert_info = X509_get_cert_info(cert);
  const X509_ALGOR* sig = X509_CINF_get_signature(cert_info);

  if (!sig) {
    return ::util::Status(Code::FAILED_PRECONDITION,
                          "cert is missing a signature");
  }

  if (EVP_PKEY_type(issuer_key->type) != EVP_PKEY_DSA) {
    return ::util::Status(Code::FAILED_PRECONDITION,
                          "issuer does not have a DSA public key");
  }

  const int alg_nid = X509_get_signature_nid(cert);

  int digest_nid;
  // We need the nid of the digest so we can create an EVP_MD for it later.
  // Should succeed as we already checked we have a DSA key
  if (!OBJ_find_sigid_algs(alg_nid, &digest_nid, nullptr)) {
    return ::util::Status(Code::INTERNAL, "lookup sigid for algorithm failed");
  }

  // Get the DER encoded certificate info from the cert
  unsigned char* der_buf(nullptr);
  const int der_length = i2d_X509_CINF(cert_info, &der_buf);
  if (der_length < 0) {
    // Failed to decode. Several possible reasons but we will just reject
    // the input rather than trying to interpret the cause
    LOG(WARNING) << "Failed to serialize the CINF component";
    LOG_OPENSSL_ERRORS(WARNING);
    return ::util::Status(Code::INVALID_ARGUMENT,
                          "failed to serialize cert info");
  }

  string der_buf_str;
  der_buf_str.assign(string(reinterpret_cast<char*>(der_buf), der_length));
  OPENSSL_free(der_buf);

  // If the key is missing parameters we don't accept it. This is allowed
  // by RFC 3279 but we have not found any examples in the wild where it's
  // used.
  if (EVP_PKEY_missing_parameters(issuer_key)) {
    LOG(WARNING) << "DSA sig check needs key params but not available";
    return ::util::Status(Code::INVALID_ARGUMENT,
                          "DSA key in cert has missing parameters");
  }

  const DSA* dsa = EVP_PKEY_get0_DSA(issuer_key);
  const EVP_MD* md = EVP_get_digestbynid(digest_nid);

  if (dsa == nullptr || md == nullptr) {
    return ::util::Status(Code::INTERNAL,
                          "failed to create hasher or get DSA sig");
  }

  unsigned char md_buffer[EVP_MAX_MD_SIZE];
  unsigned int md_size;

  // Build the digest of the cert info. Can't use higher level APIs for
  // this unfortunately as DSA is not connected up.
  if (!EVP_Digest(der_buf_str.c_str(), der_length, md_buffer, &md_size, md,
                  nullptr)) {
    return ::util::Status(Code::INTERNAL, "digest failed");
  }

  int out_valid;
  if (!DSA_check_signature(&out_valid, md_buffer, md_size,
                           cert->signature->data, cert->signature->length,
                           dsa)) {
    return ::util::Status(Code::INTERNAL, "failed to check DSA signature");
  }

  return out_valid == 1;
}

#endif
}

namespace cert_trans {


// Convert string from ASN1 and check it doesn't contain nul characters
string ASN1ToStringAndCheckForNulls(ASN1_STRING* asn1_string,
                                    const string& tag, util::Status* status) {
  const string cpp_string(reinterpret_cast<char*>(
                              ASN1_STRING_data(asn1_string)),
                          ASN1_STRING_length(asn1_string));

  // Unfortunately ASN1_STRING_length returns a signed value
  if (ASN1_STRING_length(asn1_string) < 0) {
    *status = util::Status(Code::INVALID_ARGUMENT, "ASN1 string is corrupt?");
  }

  // Make sure there isn't an embedded NUL character in the DNS ID
  // We now know it's not a negative length so this can't overflow.
  if (static_cast<size_t>(ASN1_STRING_length(asn1_string)) !=
      cpp_string.length()) {
    LOG(ERROR) << "Embedded null in asn1 string: " << tag;
    *status =
        util::Status(Code::INVALID_ARGUMENT, "Embedded null in asn1 string");
  } else {
    *status = util::Status::OK;
  }

  return cpp_string;
}


unique_ptr<Cert> Cert::FromX509(ScopedX509 x509) {
  return x509 ? unique_ptr<Cert>(new Cert(move(x509))) : nullptr;
}


Cert::Cert(ScopedX509 x509) : x509_(move(x509)) {
  CHECK(x509_);
}


unique_ptr<Cert> Cert::FromPemString(const std::string& pem_string) {
  // A read-only bio.
  ScopedBIO bio_in(BIO_new_mem_buf(const_cast<char*>(pem_string.data()),
                                   pem_string.length()));
  if (!bio_in) {
    LOG_OPENSSL_ERRORS(ERROR);
    return nullptr;
  }

  ScopedX509 x509(PEM_read_bio_X509(bio_in.get(), nullptr, nullptr, nullptr));
  if (!x509) {
    // At this point most likely the input was just corrupt. There are a few
    // real errors that may have happened (a malloc failure is one) and it is
    // virtually impossible to fish them out.
    LOG(WARNING) << "Input is not a valid PEM-encoded certificate";
    LOG_OPENSSL_ERRORS(WARNING);
  }

  return FromX509(move(x509));
}


unique_ptr<Cert> Cert::Clone() const {
  ScopedX509 x509;
  if (x509_) {
    x509.reset(X509_dup(x509_.get()));
    if (!x509) {
      LOG_OPENSSL_ERRORS(ERROR);
    }
  }
  return FromX509(move(x509));
}


unique_ptr<Cert> Cert::FromDerString(const string& der_string) {
  const unsigned char* start =
      reinterpret_cast<const unsigned char*>(der_string.data());
  ScopedX509 x509(d2i_X509(nullptr, &start, der_string.size()));
  if (!x509) {
    LOG(WARNING) << "Input is not a valid DER-encoded certificate";
    LOG_OPENSSL_ERRORS(WARNING);
  }
  return FromX509(move(x509));
}


unique_ptr<Cert> Cert::FromDerBio(BIO* bio_in) {
  ScopedX509 x509(d2i_X509_bio(CHECK_NOTNULL(bio_in), nullptr));
  if (!x509) {
    // At this point most likely the input was just corrupt. There are few
    // real errors that may have happened (a malloc failure is one) and it is
    // virtually impossible to fish them out.
    LOG(WARNING) << "Input is not a valid encoded certificate";
    LOG_OPENSSL_ERRORS(WARNING);
  }
  return FromX509(move(x509));
}


string Cert::PrintVersion() const {
  const long version(X509_get_version(CHECK_NOTNULL(x509_.get())));
  return to_string(1 + version);
}


string Cert::PrintSerialNumber() const {
  ScopedBIGNUM serial_number_BN(
      ASN1_INTEGER_to_BN(X509_get_serialNumber(CHECK_NOTNULL(x509_.get())),
                         nullptr));

  ScopedOpenSSLString serial_number_hex(BN_bn2hex(serial_number_BN.get()));

  string serial(serial_number_hex.get());
  std::transform(serial.begin(), serial.end(), serial.begin(), ::toupper);
  return serial;
}


string Cert::PrintIssuerName() const {
  return PrintName(X509_get_issuer_name(CHECK_NOTNULL(x509_.get())));
}


string Cert::PrintSubjectName() const {
  return PrintName(X509_get_subject_name(CHECK_NOTNULL(x509_.get())));
}


// static
string Cert::PrintName(X509_NAME* name) {
  if (!name)
    return string();
  ScopedBIO bio(BIO_new(BIO_s_mem()));
  if (!bio) {
    LOG_OPENSSL_ERRORS(ERROR);
    return string();
  }

  if (X509_NAME_print_ex(bio.get(), name, 0, 0) != 1) {
    LOG_OPENSSL_ERRORS(ERROR);
    return string();
  }

  string ret = util::ReadBIO(bio.get());
  return ret;
}


string Cert::PrintNotBefore() const {
  return PrintTime(X509_get_notBefore(CHECK_NOTNULL(x509_.get())));
}


string Cert::PrintNotAfter() const {
  return PrintTime(X509_get_notAfter(CHECK_NOTNULL(x509_.get())));
}


string Cert::PrintSignatureAlgorithm() const {
  const char* sigalg = OBJ_nid2ln(X509_get_signature_nid(x509_.get()));
  if (!sigalg)
    return "NULL";
  return string(sigalg);
}


// static
string Cert::PrintTime(ASN1_TIME* when) {
  if (!when)
    return string();

  ScopedBIO bio(BIO_new(BIO_s_mem()));
  if (!bio) {
    LOG_OPENSSL_ERRORS(ERROR);
    return string();
  }

  if (ASN1_TIME_print(bio.get(), when) != 1) {
    LOG_OPENSSL_ERRORS(ERROR);
    return string();
  }

  string ret = util::ReadBIO(bio.get());
  return ret;
}


bool Cert::IsIdenticalTo(const Cert& other) const {
  return X509_cmp(x509_.get(), other.x509_.get()) == 0;
}


util::StatusOr<bool> Cert::HasExtension(int extension_nid) const {
  CHECK(x509_);

  const StatusOr<int> index(ExtensionIndex(extension_nid));
  if (index.ok()) {
    return true;
  }

  if (index.status().CanonicalCode() == util::error::NOT_FOUND) {
    return false;
  }

  return util::Status(Code::INTERNAL, "Failed to get extension");
}


StatusOr<bool> Cert::HasCriticalExtension(int extension_nid) const {
  CHECK(x509_);

  const StatusOr<X509_EXTENSION*> ext(GetExtension(extension_nid));
  if (!ext.ok()) {
    // The extension may be absent, which is not an error
    if (ext.status().CanonicalCode() == util::error::NOT_FOUND) {
      return false;
    } else {
      return util::Status(Code::INTERNAL, "Failed to get extension");
    }
  }

  return X509_EXTENSION_get_critical(ext.ValueOrDie()) > 0;
}


StatusOr<bool> Cert::HasBasicConstraintCATrue() const {
  CHECK(x509_);
  const StatusOr<void*> ext_struct(ExtensionStructure(NID_basic_constraints));

  if (ext_struct.status().CanonicalCode() == Code::NOT_FOUND) {
    // No extension found
    return false;
  } else if (!ext_struct.ok()) {
    // Truly odd.
    LOG(ERROR) << "Failed to check BasicConstraints extension";
    return ext_struct.status();
  }

  // |constraints| is never null upon success.
  ScopedBASIC_CONSTRAINTS basic_constraints(
      static_cast<BASIC_CONSTRAINTS*>(ext_struct.ValueOrDie()));
  bool is_ca = basic_constraints->ca;
  return is_ca;
}


StatusOr<bool> Cert::HasExtendedKeyUsage(int key_usage_nid) const {
  CHECK(x509_);

  const ASN1_OBJECT* key_usage_obj = OBJ_nid2obj(key_usage_nid);
  if (!key_usage_obj) {
    LOG(ERROR) << "OpenSSL OBJ_nid2obj returned NULL for NID " << key_usage_nid
               << ". Is the NID not recognised?";
    LOG_OPENSSL_ERRORS(WARNING);
    return util::Status(Code::INTERNAL, "NID lookup failed");
  }

  const StatusOr<void*> ext_key_usage = ExtensionStructure(NID_ext_key_usage);

  if (ext_key_usage.status().CanonicalCode() == Code::NOT_FOUND) {
    // No extension found
    return false;
  } else if (!ext_key_usage.ok()) {
    // Truly odd.
    LOG(ERROR) << "Failed to check ExtendedKeyUsage extension";
    return ext_key_usage.status();
  }

  // |eku| is never null upon success.
  ScopedEXTENDED_KEY_USAGE eku(
      static_cast<EXTENDED_KEY_USAGE*>(ext_key_usage.ValueOrDie()));
  bool ext_key_usage_found = false;
  for (int i = 0; i < sk_ASN1_OBJECT_num(eku.get()); ++i) {
    if (OBJ_cmp(key_usage_obj, sk_ASN1_OBJECT_value(eku.get(), i)) == 0) {
      ext_key_usage_found = true;
      break;
    }
  }

  return ext_key_usage_found;
}


StatusOr<bool> Cert::IsIssuedBy(const Cert& issuer) const {
  // Seemingly no negative "real" error codes are returned from openssl api.
  return X509_check_issued(CHECK_NOTNULL(issuer.x509_.get()),
                           CHECK_NOTNULL(x509_.get())) == X509_V_OK;
}

StatusOr<bool> Cert::LogUnsupportedAlgorithm() const {
  LOG(WARNING) << "Unsupported algorithm: " << PrintSignatureAlgorithm();
  ClearOpenSSLErrors();
  return util::Status(Code::UNIMPLEMENTED, "Unsupported algorithm");
}

StatusOr<bool> Cert::IsSignedBy(const Cert& issuer) const {
  const ScopedEVP_PKEY issuer_key(
      X509_get_pubkey(CHECK_NOTNULL(issuer.x509_.get())));
  if (!issuer_key) {
    LOG(WARNING) << "NULL issuer key";
    LOG_OPENSSL_ERRORS(WARNING);
    return false;
  }

  const int ret(X509_verify(CHECK_NOTNULL(x509_.get()), issuer_key.get()));
  if (ret == 1) {
    return true;
  }

#if defined(OPENSSL_IS_BORINGSSL)
  // With BoringSSL we might have a signature algorithm that is not supported
  // by X509_verify but we still want to accept into a log. This is a weaker
  // check than x509_verify but sufficient for our needs as we are rejecting
  // spam rather than intending to trust the certificate.
  // Let's see if we can verify a DSA signature
  const StatusOr<bool> is_valid_dsa_sig =
      check_dsa_signature(x509_.get(), issuer_key.get());

  if (is_valid_dsa_sig.ok()) {
    if (is_valid_dsa_sig.ValueOrDie()) {
      ClearOpenSSLErrors();
      return true;
    } else {
      // Ensure we return the same status as we'd have got from calling
      // IsValidSignatureChain() under OpenSSL when the signature is not valid.
      return util::Status(Code::INVALID_ARGUMENT, "invalid certificate chain");
    }
  }
#endif

  unsigned long err = ERR_peek_last_error();
  const int reason = ERR_GET_REASON(err);
  const int lib = ERR_GET_LIB(err);
#if defined(OPENSSL_IS_BORINGSSL) && !defined(BORINGSSL_201603)
  // BoringSSL returns only 0 and 1.  This is an attempt to
  // approximate the circumstances that in OpenSSL cause a 0 return,
  // and that are too boring/spammy to log, e.g. malformed inputs.
  if (err == 0 || lib == ERR_LIB_ASN1 || lib == ERR_LIB_X509) {
    ClearOpenSSLErrors();
    return false;
  }

  if (lib == ERR_LIB_EVP &&
      (reason == EVP_R_UNKNOWN_MESSAGE_DIGEST_ALGORITHM ||
       reason == EVP_R_UNKNOWN_SIGNATURE_ALGORITHM)) {
    return LogUnsupportedAlgorithm();
  }
#else
  // OpenSSL and recent versions of BoringSSL use ERR_R_EVP_LIB when a
  // signature fails to verify. Clear errors in this case, but log
  // unusual failures.
  if (err == 0 || ((lib == ERR_LIB_X509 || lib == ERR_LIB_ASN1) &&
                   reason == ERR_R_EVP_LIB)) {
    ClearOpenSSLErrors();
    return false;
  }
  if (lib == ERR_LIB_ASN1 &&
      (reason == ASN1_R_UNKNOWN_MESSAGE_DIGEST_ALGORITHM ||
       reason == ASN1_R_UNKNOWN_SIGNATURE_ALGORITHM)) {
    return LogUnsupportedAlgorithm();
  }
#endif
  LOG(ERROR) << "OpenSSL X509_verify returned " << ret;
  LOG_OPENSSL_ERRORS(ERROR);
  return util::Status(Code::INTERNAL, "X509 verify error");
}


util::Status Cert::DerEncoding(string* result) const {
  unsigned char* der_buf(nullptr);
  int der_length = i2d_X509(CHECK_NOTNULL(x509_.get()), &der_buf);

  if (der_length < 0) {
    // Failed to decode. Several possible reasons but we will just reject
    // the input rather than trying to interpret the cause
    LOG(WARNING) << "Failed to serialize cert";
    LOG_OPENSSL_ERRORS(WARNING);
    return util::Status(Code::INVALID_ARGUMENT, "DER decoding failed");
  }

  result->assign(reinterpret_cast<char*>(der_buf), der_length);
  OPENSSL_free(der_buf);
  return util::Status::OK;
}


util::Status Cert::PemEncoding(string* result) const {
  ScopedBIO bp(BIO_new(BIO_s_mem()));
  if (!PEM_write_bio_X509(bp.get(), CHECK_NOTNULL(x509_.get()))) {
    LOG(WARNING) << "Failed to serialize cert";
    LOG_OPENSSL_ERRORS(WARNING);
    return util::Status(Code::INVALID_ARGUMENT, "PEM serialize failed");
  }

  char* data;
  const long len(BIO_get_mem_data(bp.get(), &data));
  CHECK_GT(len, 0);
  CHECK(data);

  result->assign(data, len);

  return util::Status::OK;
}


util::Status Cert::Sha256Digest(string* result) const {
  unsigned char digest[EVP_MAX_MD_SIZE];
  unsigned int len;
  if (X509_digest(CHECK_NOTNULL(x509_.get()), EVP_sha256(), digest, &len) !=
      1) {
    // Failed to digest. Several possible reasons but we will just reject
    // the input rather than trying to interpret the cause
    LOG(WARNING) << "Failed to compute cert digest";
    LOG_OPENSSL_ERRORS(WARNING);
    return util::Status(Code::INVALID_ARGUMENT, "SHA256 digest failed");
  }

  result->assign(reinterpret_cast<char*>(digest), len);
  return util::Status::OK;
}


util::Status Cert::DerEncodedTbsCertificate(string* result) const {
  unsigned char* der_buf(nullptr);
  int der_length = i2d_re_X509_tbs(CHECK_NOTNULL(x509_.get()), &der_buf);
  if (der_length < 0) {
    // Failed to serialize. Several possible reasons but we will just reject
    // the input rather than trying to interpret the cause
    LOG(WARNING) << "Failed to serialize the TBS component";
    LOG_OPENSSL_ERRORS(WARNING);
    return util::Status(Code::INVALID_ARGUMENT, "TBS DER serialize failed");
  }
  result->assign(reinterpret_cast<char*>(der_buf), der_length);
  OPENSSL_free(der_buf);
  return util::Status::OK;
}


util::Status Cert::DerEncodedSubjectName(string* result) const {
  return DerEncodedName(X509_get_subject_name(CHECK_NOTNULL(x509_.get())),
                        result);
}


util::Status Cert::DerEncodedIssuerName(string* result) const {
  return DerEncodedName(X509_get_issuer_name(CHECK_NOTNULL(x509_.get())),
                        result);
}


// static
util::Status Cert::DerEncodedName(X509_NAME* name, string* result) {
  unsigned char* der_buf(nullptr);
  int der_length = i2d_X509_NAME(name, &der_buf);
  if (der_length < 0) {
    // Failed to serialize. Several possible reasons but we will just reject
    // the input rather than trying to interpret the cause
    LOG(WARNING) << "Failed to serialize the subject name";
    LOG_OPENSSL_ERRORS(WARNING);
    return util::Status(Code::INVALID_ARGUMENT, "name DER serialize failed");
  }
  result->assign(reinterpret_cast<char*>(der_buf), der_length);
  OPENSSL_free(der_buf);
  return util::Status::OK;
}


util::Status Cert::PublicKeySha256Digest(string* result) const {
  unsigned char digest[EVP_MAX_MD_SIZE];
  unsigned int len;
  if (X509_pubkey_digest(CHECK_NOTNULL(x509_.get()), EVP_sha256(), digest,
                         &len) != 1) {
    // Failed to digest. Several possible reasons but we will just reject
    // the input rather than trying to interpret the cause
    LOG(WARNING) << "Failed to compute public key digest";
    LOG_OPENSSL_ERRORS(WARNING);
    return util::Status(Code::INVALID_ARGUMENT, "SHA256 digest failed");
  }
  result->assign(reinterpret_cast<char*>(digest), len);
  return util::Status::OK;
}


StatusOr<string> Cert::SPKI() const {
  unsigned char* der_buf(nullptr);
  const int der_length(
      i2d_X509_PUBKEY(X509_get_X509_PUBKEY(CHECK_NOTNULL(x509_.get())),
                      &der_buf));
  if (der_length < 0) {
    // What does this return value mean? Let's assume it means the cert
    // is bad until proven otherwise.
    LOG(WARNING) << "Failed to serialize the Subject Public Key Info";
    LOG_OPENSSL_ERRORS(WARNING);
    return util::Status(Code::INVALID_ARGUMENT, "Cert::SPKI() failed");
  }

  string result;
  result.assign(
      string(reinterpret_cast<char*>(CHECK_NOTNULL(der_buf)), der_length));

  OPENSSL_free(der_buf);
  return result;
}


util::Status Cert::SPKISha256Digest(string* result) const {
  const util::StatusOr<string> spki(SPKI());
  if (spki.ok()) {
    string sha256_digest = Sha256Hasher::Sha256Digest(spki.ValueOrDie());
    CHECK_NOTNULL(result)->assign(sha256_digest);
  }
  return spki.status();
}

util::Status Cert::OctetStringExtensionData(int extension_nid,
                                            string* result) const {
  CHECK(x509_);

  // Callers don't care whether extension is missing or invalid as they
  // usually call this method after confirming it to be present.
  const StatusOr<void*> ext_struct = ExtensionStructure(extension_nid);
  if (!ext_struct.ok() &&
      ext_struct.status().CanonicalCode() == Code::NOT_FOUND) {
    return ext_struct.status();
  }

  // |octet| is never null upon success. Caller is responsible for the
  // correctness of this cast.
  ScopedASN1_OCTET_STRING octet(
      static_cast<ASN1_OCTET_STRING*>(ext_struct.ValueOrDie()));
  result->assign(reinterpret_cast<const char*>(octet->data), octet->length);
  return util::Status::OK;
}


util::StatusOr<int> Cert::ExtensionIndex(int extension_nid) const {
  const int index(
      X509_get_ext_by_NID(CHECK_NOTNULL(x509_.get()), extension_nid, -1));
  if (index < -1) {
    // The most likely and possibly only cause for a return code
    // other than -1 is an unrecognized NID.
    LOG(ERROR) << "OpenSSL X509_get_ext_by_NID returned " << index
               << " for NID " << extension_nid
               << ". Is the NID not recognised?";
    LOG_OPENSSL_ERRORS(ERROR);
    return util::Status(util::error::INTERNAL, "X509_get_ext_by_NID error");
  }
  if (index == -1)
    return util::Status(util::error::NOT_FOUND, "extension not found");
  return index;
}


StatusOr<X509_EXTENSION*> Cert::GetExtension(int extension_nid) const {
  const StatusOr<int> extension_index(ExtensionIndex(extension_nid));
  if (!extension_index.ok()) {
    return extension_index.status();
  }

  X509_EXTENSION* const ext(
      X509_get_ext(x509_.get(), extension_index.ValueOrDie()));
  if (!ext) {
    LOG(ERROR) << "Failed to retrieve extension for NID " << extension_nid
               << ", at index " << extension_index.ValueOrDie();
    LOG_OPENSSL_ERRORS(ERROR);
    return util::Status(util::error::INTERNAL,
                        "failed to retrieve extension for NID " +
                            to_string(extension_nid) + ", at index " +
                            to_string(extension_index.ValueOrDie()));
  }

  return ext;
}


util::StatusOr<void*> Cert::ExtensionStructure(int extension_nid) const {
  // Let's first check if the extension is present. This allows us to
  // distinguish between "NID not recognized" and the more harmless
  // "extension not found, found more than once or corrupt".
  const StatusOr<bool> has_ext = HasExtension(extension_nid);
  if (!has_ext.ok()) {
    return has_ext.status();
  }

  if (!has_ext.ValueOrDie()) {
    return util::Status(Code::NOT_FOUND, "Extension NID " +
                                             to_string(extension_nid) +
                                             " not present or invalid");
  }

  int crit;

  void* ext_struct(
      X509_get_ext_d2i(x509_.get(), extension_nid, &crit, nullptr));

  if (!ext_struct) {
    if (crit != -1) {
      LOG(WARNING) << "Corrupt extension data";
      LOG_OPENSSL_ERRORS(WARNING);
    }

    return util::Status(Code::FAILED_PRECONDITION,
                        "Corrupt extension in cert?");
  }

  return ext_struct;
}


bool IsRedactedHost(const string& hostname) {
  // Split the hostname on '.' characters
  const vector<string> tokens(util::split(hostname, '.'));

  for (const string& str : tokens) {
    if (str == "?") {
      return true;
    }
  }

  return false;
}


bool IsValidRedactedHost(const string& hostname) {
  // Split the hostname on '.' characters
  const vector<string> tokens(util::split(hostname, '.'));

  // Enforces the following rules: '?' must be to left of non redactions
  // If first label is '*' then treat it as if it was a redaction
  bool can_redact = true;
  for (size_t pos = 0; pos < tokens.size(); ++pos) {
    if (tokens[pos] == "?") {
      if (!can_redact) {
        return false;
      }
    } else {
      // Allow a leading '*' for redaction but once we've seen anything else
      // forbid further redactions
      if (tokens[pos] != "*") {
        can_redact = false;
      } else if (pos > 0) {
        // '*' is only valid at the left
        return false;
      }
    }
  }

  return true;
}


namespace {

util::Status ExtractSubjectAltNames(STACK_OF(GENERAL_NAME)* subject_alt_names,
                                    vector<string>* dns_alt_names) {
  CHECK_NOTNULL(subject_alt_names);
  CHECK_NOTNULL(dns_alt_names);

  dns_alt_names->clear();
  const int subject_alt_name_count = sk_GENERAL_NAME_num(subject_alt_names);

  for (int i = 0; i < subject_alt_name_count; ++i) {
    GENERAL_NAME* const name(sk_GENERAL_NAME_value(subject_alt_names, i));

    util::Status name_status;
    if (name->type == GEN_DNS) {
      const string dns_name =
          ASN1ToStringAndCheckForNulls(name->d.dNSName, "DNS name",
                                         &name_status);

      if (!name_status.ok()) {
        return name_status;
      }

      dns_alt_names->push_back(dns_name);
    }
  }
  return util::Status::OK;
}



bool ValidateRedactionSubjectAltNames(STACK_OF(GENERAL_NAME) *
                                          subject_alt_names,
                                      vector<string>* dns_alt_names,
                                      util::Status* status,
                                      int* redacted_name_count) {
  // First. Check all the Subject Alt Name extension records. Any that are of
  // type DNS must pass validation if they are attempting to redact labels
  if (subject_alt_names) {
    *CHECK_NOTNULL(status) = ExtractSubjectAltNames(
        subject_alt_names, CHECK_NOTNULL(dns_alt_names));

    for (const auto& dns_name : *dns_alt_names) {
      if (IsRedactedHost(dns_name)) {
        if (!IsValidRedactedHost(dns_name)) {
          LOG(WARNING) << "Invalid redacted host: " << dns_name;
          *status = util::Status(Code::INVALID_ARGUMENT,
                                 "Invalid redacted hostname");
          return true;
        }

        (*redacted_name_count)++;
      }
    }
  }

  // This stage of validation is complete, result is not final yet
  return false;
}


}  // namespace


util::Status Cert::SubjectAltNames(vector<string>* dns_alt_names) const {
  ScopedGENERAL_NAMEStack subject_alt_names(
      static_cast<STACK_OF(GENERAL_NAME)*>(X509_get_ext_d2i(
          x509_.get(), NID_subject_alt_name, nullptr, nullptr)));

  if (subject_alt_names) {
    return ExtractSubjectAltNames(subject_alt_names.get(),
                                  CHECK_NOTNULL(dns_alt_names));
  }

  return util::Status::OK;
}


// Helper method for validating V2 redaction rules. If it returns true
// then the result in status is final.
bool Cert::ValidateRedactionSubjectAltNameAndCN(int* dns_alt_name_count,
                                                util::Status* status) const {
  string common_name;
  int redacted_name_count = 0;
  vector<string> dns_alt_names;

  ScopedGENERAL_NAMEStack subject_alt_names(
      static_cast<STACK_OF(GENERAL_NAME)*>(
          X509_get_ext_d2i(CHECK_NOTNULL(x509_.get()), NID_subject_alt_name,
                           nullptr, nullptr)));

  // Apply validation rules for subject alt names, if this returns true
  // status is already final.
  if (subject_alt_names &&
      ValidateRedactionSubjectAltNames(subject_alt_names.get(), &dns_alt_names,
                                       status, &redacted_name_count)) {
    return true;
  }

  // The next stage of validation is that if the subject name CN exists it
  // must match the first DNS id and have the same labels redacted
  // TODO: Confirm it's valid to not have a CN.
  X509_NAME* const name(X509_get_subject_name(x509_.get()));

  if (!name) {
    LOG(ERROR) << "Missing X509 subject name";
    *status =
        util::Status(Code::INVALID_ARGUMENT, "Missing X509 subject name");
    return true;
  }

  const int name_pos(X509_NAME_get_index_by_NID(name, NID_commonName, -1));

  if (name_pos >= 0) {
    X509_NAME_ENTRY* const name_entry(X509_NAME_get_entry(name, name_pos));

    if (name_entry) {
      ASN1_STRING* const subject_name_asn1(
          X509_NAME_ENTRY_get_data(name_entry));

      if (!subject_name_asn1) {
        LOG(WARNING) << "Missing subject name";
        // TODO: Check this is correct behaviour. Is it OK to not have
        // a subject?
      } else {
        util::Status cn_status;
        common_name =
            ASN1ToStringAndCheckForNulls(subject_name_asn1, "CN", &cn_status);

        if (!cn_status.ok()) {
          *status = cn_status;
          return true;
        }
      }
    }
  }

  // If both a subject CN and DNS ids are present in the cert then the
  // first DNS id must exactly match the CN
  if (!dns_alt_names.empty() && !common_name.empty()) {
    if (dns_alt_names[0] != common_name) {
      LOG(WARNING) << "CN " << common_name << " does not match DNS.0 "
                   << dns_alt_names[0];
      *status =
          util::Status(Code::INVALID_ARGUMENT, "CN does not match DNS.0");
      return true;
    }
  }

  // The attempted redaction passes host validation. Stage two is checking
  // that the required extensions are present and specified correctly if
  // we found any redacted names. First though if nothing is redacted
  // then the rest of the rules need not be applied
  if (redacted_name_count == 0 && !IsRedactedHost(common_name)) {
    *status = util::Status::OK;
    return true;
  }

  *dns_alt_name_count = dns_alt_names.size();
  return false;  // validation has no definite result yet
}


util::Status Cert::IsValidWildcardRedaction() const {
  util::Status status(Code::UNKNOWN, "Unknown error");
  int dns_alt_name_count = 0;

  // First we apply all the checks to the subject CN and the list of DNS
  // names in subject alt names. If these checks have a definite result
  // then return it immediately.
  if (ValidateRedactionSubjectAltNameAndCN(&dns_alt_name_count, &status)) {
    return status;
  }

  // If we reach here then the RFC says the CT redaction count extension
  // MUST BE present.
  const StatusOr<X509_EXTENSION*> exty(
      GetExtension(NID_ctPrecertificateRedactedLabelCount));
  if (!exty.ok()) {
    LOG(WARNING)
        << "required CT redaction count extension could not be found in cert";
    return util::Status(Code::INVALID_ARGUMENT,
                        "No CT redaction count extension");
  }

  // Ensure the data in the extension is a sequence. DER encoding is same for
  // SEQUENCE and SEQUENCE OF and we'll check types later.
  if (exty.ValueOrDie()->value->data[0] !=
      (V_ASN1_SEQUENCE | V_ASN1_CONSTRUCTED)) {
    LOG(WARNING) << "CT redaction count extension is not a SEQUENCE OF";
    return util::Status(Code::INVALID_ARGUMENT,
                        "CT redaction count extension not a sequence");
  }

  // Unpack the extension contents, which should be SEQUENCE OF INTEGER.
  // For compatibility we unpack any sequence and check integer type as we go.
  // Don't pass the pointer from the extension directly as it gets incremented
  // during parsing.
  const unsigned char* sequence_data(
      const_cast<const unsigned char*>(exty.ValueOrDie()->value->data));
  ScopedASN1_TYPEStack asn1_types(static_cast<STACK_OF(ASN1_TYPE)*>(
      d2i_ASN1_SEQUENCE_ANY(nullptr, &sequence_data,
                            exty.ValueOrDie()->value->length)));

  if (asn1_types) {
    const int num_integers(sk_ASN1_TYPE_num(asn1_types.get()));

    // RFC text says there MUST NOT be more integers than there are DNS ids
    if (num_integers > dns_alt_name_count) {
      LOG(WARNING) << "Too many integers in extension: " << num_integers
                   << " but only " << dns_alt_name_count << " DNS names";
      return util::Status(Code::INVALID_ARGUMENT,
                          "More integers in ext than redacted labels");
    }

    // All the integers in the sequence must be positive, check the sign
    // after conversion to BIGNUM
    for (int i = 0; i < num_integers; ++i) {
      ASN1_TYPE* const asn1_type(sk_ASN1_TYPE_value(asn1_types.get(), i));

      if (asn1_type->type != V_ASN1_INTEGER) {
        LOG(WARNING) << "Redaction count has non-integer in sequence"
                     << asn1_type->type;
        return util::Status(Code::INVALID_ARGUMENT,
                            "Non integer found in redaction label count");
      }

      ASN1_INTEGER* const redacted_labels(asn1_type->value.integer);
      ScopedBIGNUM value(ASN1_INTEGER_to_BN(redacted_labels, nullptr));

      const bool neg = value->neg;
      if (neg) {
        ScopedOpenSSLString bn_hex(BN_bn2hex(value.get()));
        LOG(WARNING) << "Invalid negative redaction label count: "
                     << bn_hex.get();
        return util::Status(Code::INVALID_ARGUMENT, "Invalid -ve label count");
      }
    }

  } else {
    LOG(WARNING) << "Failed to unpack SEQUENCE OF in CT extension";
    return util::Status(Code::INVALID_ARGUMENT,
                        "Failed to unpack integer sequence in ext");
  }

  return util::Status::OK;
}


util::Status Cert::IsValidNameConstrainedIntermediateCa() const {
  // If it's not a CA cert or there is no name constraint extension then we
  // don't need to apply the rules any further
  const StatusOr<bool> has_ca_constraint = HasBasicConstraintCATrue();
  const StatusOr<bool> has_name_constraints =
      HasExtension(NID_name_constraints);

  // However, we don't expect either of the above lookups to fail as the
  // extensions are registered.
  if (!has_ca_constraint.ok()) {
    return has_ca_constraint.status();
  }

  if (!has_name_constraints.ok()) {
    return has_name_constraints.status();
  }

  if (!has_ca_constraint.ValueOrDie() || !has_name_constraints.ValueOrDie()) {
    return util::Status::OK;
  }

  // So there now must be a CT extension and the name constraint must not be
  // in error
  const StatusOr<bool> has_ct_nolog_intermediate =
      HasExtension(NID_ctNameConstraintNologIntermediateCa);

  CHECK(has_name_constraints.ValueOrDie());
  if (!has_ct_nolog_intermediate.ok() ||
      !has_ct_nolog_intermediate.ValueOrDie()) {
    LOG(WARNING) << "Name constraint extension without CT extension";
    return util::Status(Code::INVALID_ARGUMENT,
                        "Name constraint ext present, CT ext missing");
  }

  int crit;
  NAME_CONSTRAINTS* const nc(static_cast<NAME_CONSTRAINTS*>(
      X509_get_ext_d2i(x509_.get(), NID_name_constraints, &crit, nullptr)));

  if (!nc || crit == -1) {
    LOG(ERROR) << "Couldn't parse the name constraint extension";
    return util::Status(Code::INTERNAL, "Failed to parse name constraint");
  }

  // Search all the permitted subtrees, there must be at least one DNS
  // entry and it must not be empty
  bool seen_dns = false;

  for (int permitted_subtree = 0;
       permitted_subtree < sk_GENERAL_SUBTREE_num(nc->permittedSubtrees);
       ++permitted_subtree) {
    GENERAL_SUBTREE* const perm_subtree(
        sk_GENERAL_SUBTREE_value(nc->permittedSubtrees, permitted_subtree));

    if (perm_subtree->base && perm_subtree->base->type == GEN_DNS &&
        perm_subtree->base->d.dNSName->length > 0) {
      seen_dns = true;
    }
  }

  // There must be an excluded subtree entry that covers the whole IPv4 and
  // IPv6 range. Or at least one entry for both that covers the whole
  // range
  bool seen_ipv4 = false;
  bool seen_ipv6 = false;

  // TODO: Does not handle more complex cases at the moment and I'm
  // not sure whether it should. E.g. a combination of multiple entries
  // that end up covering the whole available range. For the moment
  // things similar to the example in the RFC work.
  for (int excluded_subtree = 0;
       excluded_subtree < sk_GENERAL_SUBTREE_num(nc->excludedSubtrees);
       ++excluded_subtree) {
    GENERAL_SUBTREE* const excl_subtree(
        sk_GENERAL_SUBTREE_value(nc->excludedSubtrees, excluded_subtree));

    // Only consider entries that are of type ipAddress (OCTET_STRING)
    if (excl_subtree->base && excl_subtree->base->type == GEN_IPADD) {
      // First check that all the bytes of the string are zero
      bool all_zero = true;
      for (int i = 0; i < excl_subtree->base->d.ip->length; ++i) {
        if (excl_subtree->base->d.ip->data[i] != 0) {
          all_zero = false;
        }
      }

      if (all_zero) {
        if (excl_subtree->base->d.ip->length == 32) {
          // IPv6
          seen_ipv6 = true;
        } else if (excl_subtree->base->d.ip->length == 8) {
          // IPv4
          seen_ipv4 = true;
        }
      }
    }
  }

  NAME_CONSTRAINTS_free(nc);

  if (!seen_dns) {
    LOG(WARNING) << "No DNS entry found in permitted subtrees";
    return util::Status(Code::INVALID_ARGUMENT,
                        "No DNS entry in permitted subtrees");
  }

  if (!seen_ipv4 || !seen_ipv6) {
    LOG(WARNING) << "Excluded subtree does not cover all IPv4 and v6 range";
    return util::Status(Code::INVALID_ARGUMENT,
                        "Does not exclude all IPv4 and v6 range");
  }

  return util::Status::OK;
}

TbsCertificate::TbsCertificate(const Cert& cert) {
  x509_.reset(X509_dup(CHECK_NOTNULL(cert.x509_.get())));

  if (!x509_)
    LOG_OPENSSL_ERRORS(ERROR);
}


util::Status TbsCertificate::DerEncoding(string* result) const {
  if (!IsLoaded()) {
    LOG(ERROR) << "TBS not loaded";
    return util::Status(Code::FAILED_PRECONDITION, "Cert not loaded (TBS)");
  }

  unsigned char* der_buf(nullptr);
  int der_length = i2d_re_X509_tbs(x509_.get(), &der_buf);
  if (der_length < 0) {
    // Failed to serialize. Several possible reasons but we will just reject
    // the input rather than trying to interpret the cause
    LOG(WARNING) << "Failed to serialize the TBS component";
    LOG_OPENSSL_ERRORS(WARNING);
    return util::Status(Code::INTERNAL, "Failed to serialize TBS");
  }
  result->assign(reinterpret_cast<char*>(der_buf), der_length);
  OPENSSL_free(der_buf);
  return util::Status::OK;
}


util::Status TbsCertificate::DeleteExtension(int extension_nid) {
  if (!IsLoaded()) {
    LOG(ERROR) << "TBS not loaded";
    return util::Status(Code::FAILED_PRECONDITION, "Cert not loaded (TBS)");
  }

  const StatusOr<int> extension_index(ExtensionIndex(extension_nid));
  // If the extension doesn't exist then there is nothing to do and this
  // propagates the NOT_FOUND status.
  if (!extension_index.ok()) {
    return extension_index.status();
  }

  ScopedX509_EXTENSION ext(
      X509_delete_ext(x509_.get(), extension_index.ValueOrDie()));

  if (!ext) {
    // Truly odd.
    LOG(ERROR) << "Failed to delete the extension";
    LOG_OPENSSL_ERRORS(ERROR);
    return util::Status(Code::INTERNAL, "Failed to delete extension");
  }


  // ExtensionIndex returns the first matching index - if the extension
  // occurs more than once, just give up.
  const StatusOr<int> ignored_index(ExtensionIndex(extension_nid));
  if (ignored_index.ok()) {
    LOG(WARNING)
        << "Failed to delete the extension. Does the certificate have "
        << "duplicate extensions?";
    return util::Status(Code::ALREADY_EXISTS, "Multiple extensions in cert");
  }

  // It's not an error if the extension didn't exist the second time
  // as it should have been deleted.
  if (!ignored_index.ok() &&
      ignored_index.status().CanonicalCode() != Code::NOT_FOUND) {
    return ignored_index.status();
  }

  return util::Status::OK;
}


util::Status TbsCertificate::CopyIssuerFrom(const Cert& from) {
  if (!IsLoaded()) {
    LOG(ERROR) << "TBS not loaded";
    return util::Status(Code::FAILED_PRECONDITION, "Cert not loaded (TBS)");
  }

  // This just looks up the relevant pointer so there shouldn't
  // be any errors to clear.
  X509_NAME* ca_name = X509_get_issuer_name(from.x509_.get());
  if (!ca_name) {
    LOG(WARNING) << "Issuer certificate has NULL name";
    return util::Status(Code::FAILED_PRECONDITION,
                        "Issuer cert has NULL name");
  }

  if (X509_set_issuer_name(x509_.get(), ca_name) != 1) {
    LOG(WARNING) << "Failed to set issuer name, Cert has NULL issuer?";
    LOG_OPENSSL_ERRORS(WARNING);
    return util::Status(Code::FAILED_PRECONDITION,
                        "Failed to set issuer, possibly null?");
  }

  // Verify that the Authority KeyID extensions are compatible.
  StatusOr<int> status = ExtensionIndex(NID_authority_key_identifier);
  if (status.status().CanonicalCode() == Code::NOT_FOUND) {
    // No extension found = nothing to copy
    return util::Status::OK;
  }

  if (!status.ok() || !status.ValueOrDie()) {
    LOG(ERROR) << "Failed to check Authority Key Identifier extension";
    return util::Status(Code::INTERNAL,
                        "Failed to check Authority KeyID extension (TBS)");
  }

  const StatusOr<int> from_extension_index(
      from.ExtensionIndex(NID_authority_key_identifier));
  if (from_extension_index.status().CanonicalCode() ==
      util::error::NOT_FOUND) {
    // No extension found = cannot copy.
    LOG(WARNING) << "Unable to copy issuer: destination has an Authority "
                 << "KeyID extension, but the source has none.";
    return util::Status(Code::FAILED_PRECONDITION,
                        "Incompatible Authority KeyID extensions");
  }

  if (!from_extension_index.ok()) {
    LOG(ERROR) << "Failed to check Authority Key Identifier extension";
    return util::Status(Code::INTERNAL,
                        "Failed to check Authority KeyID extension");
  }

  // Ok, now copy the extension, keeping the critical bit (which should always
  // be false in a valid cert, mind you).
  X509_EXTENSION* to_ext = X509_get_ext(x509_.get(), status.ValueOrDie());
  X509_EXTENSION* from_ext =
      X509_get_ext(from.x509_.get(), from_extension_index.ValueOrDie());

  if (!to_ext || !from_ext) {
    // Should not happen.
    LOG(ERROR) << "Failed to retrieve extension";
    LOG_OPENSSL_ERRORS(ERROR);
    return util::Status(Code::INTERNAL,
                        "Failed to retrieve one or both extensions");
  }

  if (X509_EXTENSION_set_data(to_ext, X509_EXTENSION_get_data(from_ext)) !=
      1) {
    LOG(ERROR) << "Failed to copy extension data.";
    LOG_OPENSSL_ERRORS(ERROR);
    return util::Status(Code::INTERNAL, "Failed to copy extension data");
  }

  return util::Status::OK;
}


StatusOr<int> TbsCertificate::ExtensionIndex(int extension_nid) const {
  int index = X509_get_ext_by_NID(x509_.get(), extension_nid, -1);
  if (index < -1) {
    // The most likely and possibly only cause for a return code
    // other than -1 is an unrecognized NID. This is different from a
    // known extension not being present.
    LOG(ERROR) << "OpenSSL X509_get_ext_by_NID returned " << index
               << " for NID " << extension_nid
               << ". Is the NID not recognised?";
    LOG_OPENSSL_ERRORS(ERROR);
    return util::Status(Code::INTERNAL,
                        "Extension lookup failed. Incorrect NID?");
  }
  if (index == -1) {
    return util::Status(Code::NOT_FOUND, "Extension not found.");
  }

  return index;
}


CertChain::CertChain(const string& pem_string) {
  // A read-only BIO.
  ScopedBIO bio_in(BIO_new_mem_buf(const_cast<char*>(pem_string.data()),
                                   pem_string.length()));
  if (!bio_in) {
    LOG_OPENSSL_ERRORS(ERROR);
    return;
  }

  ScopedX509 x509;
  while ((x509 = ScopedX509(
              PEM_read_bio_X509(bio_in.get(), nullptr, nullptr, nullptr)))) {
    chain_.push_back(Cert::FromX509(move(x509)));
  }

  // The last error must be EOF.
  unsigned long err = ERR_peek_last_error();
  if (ERR_GET_LIB(err) != ERR_LIB_PEM ||
      ERR_GET_REASON(err) != PEM_R_NO_START_LINE) {
    // A real error.
    LOG(WARNING) << "Input is not a valid PEM-encoded certificate chain";
    LOG_OPENSSL_ERRORS(WARNING);
    ClearChain();
  } else {
    ClearOpenSSLErrors();
  }
}


bool CertChain::AddCert(unique_ptr<Cert> cert) {
  if (!cert) {
    LOG(ERROR) << "Attempting to add an invalid cert";
    return false;
  }
  chain_.push_back(move(cert));
  return true;
}


void CertChain::RemoveCert() {
  if (IsLoaded()) {
    chain_.pop_back();
  } else {
    LOG(ERROR) << "Chain is not loaded";
  }
}


bool CertChain::RemoveCertsAfterFirstSelfSigned() {
  if (!IsLoaded()) {
    LOG(ERROR) << "Chain is not loaded";
    return false;
  }

  size_t first_self_signed = chain_.size();

  // Find the first self-signed certificate.
  for (size_t i = 0; i < chain_.size(); ++i) {
    StatusOr<bool> status = chain_[i]->IsSelfSigned();
    if (!status.ok()) {
      return false;
    } else if (status.ValueOrDie()) {
      first_self_signed = i;
      break;
    }
  }

  if (first_self_signed == chain_.size())
    return true;

  // Remove everything after it.
  size_t chain_size = chain_.size();
  for (size_t i = first_self_signed + 1; i < chain_size; ++i) {
    RemoveCert();
  }
  return true;
}


CertChain::~CertChain() {
  ClearChain();
}


util::Status CertChain::IsValidCaIssuerChainMaybeLegacyRoot() const {
  if (!IsLoaded()) {
    LOG(ERROR) << "Chain is not loaded";
    return util::Status(Code::FAILED_PRECONDITION, "Cert not loaded");
  }

  for (vector<unique_ptr<Cert>>::const_iterator it = chain_.begin();
       it + 1 < chain_.end(); ++it) {
    const unique_ptr<Cert>& subject = *it;
    const unique_ptr<Cert>& issuer = *(it + 1);

    // The root cert may not have CA:True
    const StatusOr<bool> status = issuer->IsSelfSigned();
    if (status.ok() && !status.ValueOrDie()) {
      const StatusOr<bool> s2(issuer->HasBasicConstraintCATrue());
      if (!s2.ok() || !s2.ValueOrDie()) {
        return util::Status(Code::INVALID_ARGUMENT,
                            "CA constraint check failed");
      }
    } else if (!status.ok()) {
      LOG(ERROR) << "Failed to check self-signed status";
      return util::Status(Code::INVALID_ARGUMENT,
                          "Failed to check self signed status");
    }

    const StatusOr<bool> s3 = subject->IsIssuedBy(*issuer);
    if (!s3.ok() || !s3.ValueOrDie()) {
      return util::Status(Code::INVALID_ARGUMENT, "Issuer check failed");
    }
  }
  return util::Status::OK;
}


util::Status CertChain::IsValidSignatureChain() const {
  if (!IsLoaded()) {
    LOG(ERROR) << "Chain is not loaded";
    return util::Status(util::error::FAILED_PRECONDITION,
                        "certificate chain is not loaded");
  }

  for (vector<unique_ptr<Cert>>::const_iterator it = chain_.begin();
       it + 1 < chain_.end(); ++it) {
    const unique_ptr<Cert>& subject = *it;
    const unique_ptr<Cert>& issuer = *(it + 1);

    const StatusOr<bool> status = subject->IsSignedBy(*issuer);

    // Propagate any failure status if we get one. This includes
    // UNIMPLEMENTED for unsupported algorithms. This can happen
    // when a weak algorithm (such as MD2) is intentionally not
    // accepted in which case it's correct to say that the chain is invalid.
    // It can also happen when EVP is not properly initialized, in
    // which case it's more of an INTERNAL_ERROR. However a bust
    // setup would manifest itself in many other ways, including
    // failing tests, so we assume the failure is intentional.
    if (!status.ok()) {
      return status.status();
    }

    // Must have been signed by issuer or it's an invalid chain
    if (!status.ValueOrDie()) {
      return util::Status(util::error::INVALID_ARGUMENT,
                          "invalid certificate chain");
    }
  }

  return util::Status::OK;
}


void CertChain::ClearChain() {
  chain_.clear();
}


util::StatusOr<bool> PreCertChain::UsesPrecertSigningCertificate() const {
  const Cert* issuer = PrecertIssuingCert();
  if (!issuer) {
    // No issuer, so it must be a real root CA from the store.
    return false;
  }

  return issuer->HasExtendedKeyUsage(cert_trans::NID_ctPrecertificateSigning);
}


util::StatusOr<bool> PreCertChain::IsWellFormed() const {
  if (!IsLoaded()) {
    LOG(ERROR) << "Chain is not loaded";
    return util::Status(Code::FAILED_PRECONDITION, "Cert not loaded");
  }

  const Cert* pre = PreCert();

  // (1) Check that the leaf contains the critical poison extension.
  const StatusOr<bool> has_poison =
      pre->HasCriticalExtension(cert_trans::NID_ctPoison);
  if (!has_poison.ok() || !has_poison.ValueOrDie()) {
    return has_poison;
  }

  // (2) If signed by a Precertificate Signing Certificate, check that
  // the AKID extensions are compatible.
  const StatusOr<bool> uses_precert_signing = UsesPrecertSigningCertificate();
  if (uses_precert_signing.ok() && !uses_precert_signing.ValueOrDie()) {
    // If there is no precert signing extendedKeyUsage, no more checks:
    // the cert was issued by a regular CA.
    return true;
  }

  if (!uses_precert_signing.ok()) {
    return uses_precert_signing.status();
  }

  CHECK(uses_precert_signing.ValueOrDie());

  const Cert* issuer = PrecertIssuingCert();
  // If pre has the extension set but the issuer doesn't, error.
  const StatusOr<bool> has_akid =
      pre->HasExtension(NID_authority_key_identifier);

  if (has_akid.ok() && !has_akid.ValueOrDie()) {
    return true;
  }
  if (!has_akid.ok()) {
    return has_akid;
  }

  CHECK(has_akid.ValueOrDie());

  // Extension present in the leaf: check it's present in the issuer.
  return issuer->HasExtension(NID_authority_key_identifier);
}


}  // namespace cert_trans