1 /* ***** BEGIN LICENSE BLOCK *****
2 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
4 * The contents of this file are subject to the Mozilla Public License Version
5 * 1.1 (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 * http://www.mozilla.org/MPL/
9 * Software distributed under the License is distributed on an "AS IS" basis,
10 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
11 * for the specific language governing rights and limitations under the
14 * The Original Code is the Netscape security libraries.
16 * The Initial Developer of the Original Code is
17 * Netscape Communications Corporation.
18 * Portions created by the Initial Developer are Copyright (C) 1994-2000
19 * the Initial Developer. All Rights Reserved.
23 * Alternatively, the contents of this file may be used under the terms of
24 * either the GNU General Public License Version 2 or later (the "GPL"), or
25 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
26 * in which case the provisions of the GPL or the LGPL are applicable instead
27 * of those above. If you wish to allow use of your version of this file only
28 * under the terms of either the GPL or the LGPL, and not to allow others to
29 * use your version of this file under the terms of the MPL, indicate your
30 * decision by deleting the provisions above and replace them with the notice
31 * and other provisions required by the GPL or the LGPL. If you do not delete
32 * the provisions above, a recipient may use your version of this file under
33 * the terms of any one of the MPL, the GPL or the LGPL.
35 * ***** END LICENSE BLOCK ***** */
43 /* maximum supported modulus length in bits (indicate problem if over this) */
44 #define MAX_MODULUS (1024)
47 static void Usage(char *progName
)
49 fprintf(stderr
, "Usage: %s [aAvf] [certtocheck] [issuingcert]\n",
51 fprintf(stderr
, "%-20s Cert to check is base64 encoded\n",
53 fprintf(stderr
, "%-20s Issuer's cert is base64 encoded\n",
55 fprintf(stderr
, "%-20s Verbose (indicate decoding progress etc.)\n",
57 fprintf(stderr
, "%-20s Force sanity checks even if pretty print fails.\n",
59 fprintf(stderr
, "%-20s Define an output file to use (default is stdout)\n",
61 fprintf(stderr
, "%-20s Specify the input type (no default)\n",
68 * Check integer field named fieldName, printing out results and
69 * returning the length of the integer in bits
73 int checkInteger(SECItem
*intItem
, char *fieldName
, int verbose
)
77 printf("Checking %s\n", fieldName
);
82 if (len
&& (intItem
->data
[0] & 0x80)) {
83 printf("PROBLEM: %s is NEGATIVE 2's-complement integer.\n",
88 /* calculate bit length and check for unnecessary leading zeros */
90 if (len
> 1 && intItem
->data
[0] == 0) {
91 /* leading zero byte(s) */
92 if (!(intItem
->data
[1] & 0x80)) {
93 printf("PROBLEM: %s has unneeded leading zeros. Violates DER.\n",
96 /* strip leading zeros in length calculation */
99 while (bitlen
> 8 && intItem
->data
[i
] == 0) {
112 void checkName(CERTName
*n
, char *fieldName
, int verbose
)
116 printf("Checking %s\n", fieldName
);
119 v
= CERT_GetCountryName(n
);
121 printf("PROBLEM: %s lacks Country Name (C)\n",
126 v
= CERT_GetOrgName(n
);
128 printf("PROBLEM: %s lacks Organization Name (O)\n",
133 v
= CERT_GetOrgUnitName(n
);
135 printf("WARNING: %s lacks Organization Unit Name (OU)\n",
140 v
= CERT_GetCommonName(n
);
142 printf("PROBLEM: %s lacks Common Name (CN)\n",
151 OurVerifyData(unsigned char *buf
, int len
, SECKEYPublicKey
*key
,
152 SECItem
*sig
, SECAlgorithmID
*sigAlgorithm
)
156 SECOidData
*sigAlgOid
, *oiddata
;
158 SECOidTag hashAlgTag
;
161 cx
= VFY_CreateContextWithAlgorithmID(key
, sig
, sigAlgorithm
, &hashAlgTag
,
166 sigAlgOid
= SECOID_FindOID(&sigAlgorithm
->algorithm
);
169 sigAlgTag
= sigAlgOid
->offset
;
173 oiddata
= SECOID_FindOIDByTag(hashAlgTag
);
175 printf("PROBLEM: (cont) Digest OID is %s\n", oiddata
->desc
);
177 SECU_PrintAsHex(stdout
,
178 &oiddata
->oid
, "PROBLEM: UNKNOWN OID", 0);
183 if (rv
== SECSuccess
) {
184 rv
= VFY_Update(cx
, buf
, len
);
185 if (rv
== SECSuccess
)
189 VFY_DestroyContext(cx
, PR_TRUE
);
197 OurVerifySignedData(CERTSignedData
*sd
, CERTCertificate
*cert
)
200 SECKEYPublicKey
*pubKey
= 0;
203 /* check the certificate's validity */
204 rv
= CERT_CertTimesValid(cert
);
209 /* get cert's public key */
210 pubKey
= CERT_ExtractPublicKey(cert
);
215 /* check the signature */
217 DER_ConvertBitString(&sig
);
218 rv
= OurVerifyData(sd
->data
.data
, sd
->data
.len
, pubKey
, &sig
,
219 &sd
->signatureAlgorithm
);
221 SECKEY_DestroyPublicKey(pubKey
);
234 CERTCertificate
*createEmptyCertificate(void)
236 PRArenaPool
*arena
= 0;
237 CERTCertificate
*c
= 0;
239 arena
= PORT_NewArena(DER_DEFAULT_CHUNKSIZE
);
245 c
= (CERTCertificate
*) PORT_ArenaZAlloc(arena
, sizeof(CERTCertificate
));
248 c
->referenceCount
= 1;
251 PORT_FreeArena(arena
,PR_TRUE
);
260 int main(int argc
, char **argv
)
262 int rv
, verbose
=0, force
=0;
263 int ascii
=0, issuerAscii
=0;
265 PRFileDesc
*inFile
=0, *issuerCertFile
=0;
266 SECItem derCert
, derIssuerCert
;
267 PRArenaPool
*arena
=0;
268 CERTSignedData
*signedData
=0;
269 CERTCertificate
*cert
=0, *issuerCert
=0;
270 SECKEYPublicKey
*rsapubkey
=0;
271 SECAlgorithmID md5WithRSAEncryption
, md2WithRSAEncryption
;
272 SECAlgorithmID sha1WithRSAEncryption
, rsaEncryption
;
276 char *inFileName
= NULL
, *issuerCertFileName
= NULL
;
277 PLOptState
*optstate
;
280 PORT_Memset(&md5WithRSAEncryption
, 0, sizeof(md5WithRSAEncryption
));
281 PORT_Memset(&md2WithRSAEncryption
, 0, sizeof(md2WithRSAEncryption
));
282 PORT_Memset(&sha1WithRSAEncryption
, 0, sizeof(sha1WithRSAEncryption
));
283 PORT_Memset(&rsaEncryption
, 0, sizeof(rsaEncryption
));
285 progName
= strrchr(argv
[0], '/');
286 progName
= progName
? progName
+1 : argv
[0];
288 optstate
= PL_CreateOptState(argc
, argv
, "aAvf");
289 while ((status
= PL_GetNextOpt(optstate
)) == PL_OPT_OK
) {
290 switch (optstate
->option
) {
309 inFileName
= PL_strdup(optstate
->value
);
310 else if (!issuerCertFileName
)
311 issuerCertFileName
= PL_strdup(optstate
->value
);
318 if (!inFileName
|| !issuerCertFileName
|| status
== PL_OPT_BAD
) {
319 /* insufficient or excess args */
323 inFile
= PR_Open(inFileName
, PR_RDONLY
, 0);
325 fprintf(stderr
, "%s: unable to open \"%s\" for reading\n",
326 progName
, inFileName
);
330 issuerCertFile
= PR_Open(issuerCertFileName
, PR_RDONLY
, 0);
331 if (!issuerCertFile
) {
332 fprintf(stderr
, "%s: unable to open \"%s\" for reading\n",
333 progName
, issuerCertFileName
);
337 if (SECU_ReadDERFromFile(&derCert
, inFile
, ascii
) != SECSuccess
) {
338 printf("Couldn't read input certificate as DER binary or base64\n");
342 arena
= PORT_NewArena(DER_DEFAULT_CHUNKSIZE
);
344 fprintf(stderr
,"%s: can't allocate scratch arena!", progName
);
348 if (issuerCertFile
) {
349 CERTSignedData
*issuerCertSD
=0;
350 if (SECU_ReadDERFromFile(&derIssuerCert
, issuerCertFile
, issuerAscii
)
352 printf("Couldn't read issuer certificate as DER binary or base64.\n");
355 issuerCertSD
= PORT_ArenaZNew(arena
, CERTSignedData
);
357 fprintf(stderr
,"%s: can't allocate issuer signed data!", progName
);
360 rv
= SEC_ASN1DecodeItem(arena
, issuerCertSD
,
361 SEC_ASN1_GET(CERT_SignedDataTemplate
),
364 fprintf(stderr
, "%s: Issuer cert isn't X509 SIGNED Data?\n",
368 issuerCert
= createEmptyCertificate();
370 printf("%s: can't allocate space for issuer cert.", progName
);
373 rv
= SEC_ASN1DecodeItem(arena
, issuerCert
,
374 SEC_ASN1_GET(CERT_CertificateTemplate
),
375 &issuerCertSD
->data
);
377 printf("%s: Does not appear to be an X509 Certificate.\n",
383 signedData
= PORT_ArenaZNew(arena
,CERTSignedData
);
385 fprintf(stderr
,"%s: can't allocate signedData!", progName
);
389 rv
= SEC_ASN1DecodeItem(arena
, signedData
,
390 SEC_ASN1_GET(CERT_SignedDataTemplate
),
393 fprintf(stderr
, "%s: Does not appear to be X509 SIGNED Data.\n",
399 printf("Decoded ok as X509 SIGNED data.\n");
402 cert
= createEmptyCertificate();
404 fprintf(stderr
, "%s: can't allocate cert", progName
);
408 rv
= SEC_ASN1DecodeItem(arena
, cert
,
409 SEC_ASN1_GET(CERT_CertificateTemplate
),
412 fprintf(stderr
, "%s: Does not appear to be an X509 Certificate.\n",
419 printf("Decoded ok as an X509 certificate.\n");
422 SECU_RegisterDynamicOids();
423 rv
= SECU_PrintSignedData(stdout
, &derCert
, "Certificate", 0,
424 SECU_PrintCertificate
);
427 fprintf(stderr
, "%s: Unable to pretty print cert. Error: %d\n",
428 progName
, PORT_GetError());
435 /* Do various checks on the cert */
439 /* Check algorithms */
440 SECOID_SetAlgorithmID(arena
, &md5WithRSAEncryption
,
441 SEC_OID_PKCS1_MD5_WITH_RSA_ENCRYPTION
, NULL
);
443 SECOID_SetAlgorithmID(arena
, &md2WithRSAEncryption
,
444 SEC_OID_PKCS1_MD2_WITH_RSA_ENCRYPTION
, NULL
);
446 SECOID_SetAlgorithmID(arena
, &sha1WithRSAEncryption
,
447 SEC_OID_PKCS1_SHA1_WITH_RSA_ENCRYPTION
, NULL
);
449 SECOID_SetAlgorithmID(arena
, &rsaEncryption
,
450 SEC_OID_PKCS1_RSA_ENCRYPTION
, NULL
);
453 int isMD5RSA
= (SECOID_CompareAlgorithmID(&cert
->signature
,
454 &md5WithRSAEncryption
) == 0);
455 int isMD2RSA
= (SECOID_CompareAlgorithmID(&cert
->signature
,
456 &md2WithRSAEncryption
) == 0);
457 int isSHA1RSA
= (SECOID_CompareAlgorithmID(&cert
->signature
,
458 &sha1WithRSAEncryption
) == 0);
461 printf("\nDoing algorithm checks.\n");
464 if (!(isMD5RSA
|| isMD2RSA
|| isSHA1RSA
)) {
465 printf("PROBLEM: Signature not PKCS1 MD5, MD2, or SHA1 + RSA.\n");
466 } else if (!isMD5RSA
) {
467 printf("WARNING: Signature not PKCS1 MD5 with RSA Encryption\n");
470 if (SECOID_CompareAlgorithmID(&cert
->signature
,
471 &signedData
->signatureAlgorithm
)) {
472 printf("PROBLEM: Algorithm in sig and certInfo don't match.\n");
476 if (SECOID_CompareAlgorithmID(&cert
->subjectPublicKeyInfo
.algorithm
,
478 printf("PROBLEM: Public key algorithm is not PKCS1 RSA Encryption.\n");
481 /* Check further public key properties */
482 spk
= cert
->subjectPublicKeyInfo
.subjectPublicKey
;
483 DER_ConvertBitString(&spk
);
486 printf("\nsubjectPublicKey DER\n");
487 rv
= DER_PrettyPrint(stdout
, &spk
, PR_FALSE
);
491 rsapubkey
= (SECKEYPublicKey
*)
492 PORT_ArenaZAlloc(arena
,sizeof(SECKEYPublicKey
));
494 fprintf(stderr
, "%s: rsapubkey allocation failed.\n", progName
);
498 rv
= SEC_ASN1DecodeItem(arena
, rsapubkey
,
499 SEC_ASN1_GET(SECKEY_RSAPublicKeyTemplate
), &spk
);
501 printf("PROBLEM: subjectPublicKey is not a DER PKCS1 RSAPublicKey.\n");
506 printf("Decoded RSA Public Key ok. Doing key checks.\n");
508 PORT_Assert(rsapubkey
->keyType
== rsaKey
); /* XXX RSA */
509 mlen
= checkInteger(&rsapubkey
->u
.rsa
.modulus
, "Modulus", verbose
);
510 printf("INFO: Public Key modulus length in bits: %d\n", mlen
);
511 if (mlen
> MAX_MODULUS
) {
512 printf("PROBLEM: Modulus length exceeds %d bits.\n",
516 printf("WARNING: Short modulus.\n");
518 if (mlen
!= (1 << (ffs(mlen
)-1))) {
519 printf("WARNING: Unusual modulus length (not a power of two).\n");
521 checkInteger(&rsapubkey
->u
.rsa
.publicExponent
, "Public Exponent",
523 pubexp
= DER_GetInteger(&rsapubkey
->u
.rsa
.publicExponent
);
524 if (pubexp
!= 17 && pubexp
!= 3 && pubexp
!= 65537) {
525 printf("WARNING: Public exponent not any of: 3, 17, 65537\n");
531 checkName(&cert
->issuer
, "Issuer Name", verbose
);
532 checkName(&cert
->subject
, "Subject Name", verbose
);
536 CERT_CompareName(&cert
->issuer
, &issuerCert
->subject
);
538 printf("PROBLEM: Issuer Name and Subject in Issuing Cert differ\n");
542 /* Check if self-signed */
543 selfSigned
= (CERT_CompareName(&cert
->issuer
, &cert
->subject
) == 0);
545 printf("INFO: Certificate is self signed.\n");
547 printf("INFO: Certificate is NOT self-signed.\n");
551 /* Validity time check */
552 if (CERT_CertTimesValid(cert
) == SECSuccess
) {
553 printf("INFO: Inside validity period of certificate.\n");
555 printf("PROBLEM: Not in validity period of certificate.\n");
559 /* Signature check if self-signed */
560 if (selfSigned
&& !invalid
) {
561 if (rsapubkey
->u
.rsa
.modulus
.len
) {
564 printf("Checking self signature.\n");
566 ver
= OurVerifySignedData(signedData
, cert
);
567 if (ver
!= SECSuccess
) {
568 printf("PROBLEM: Verification of self-signature failed!\n");
570 printf("INFO: Self-signature verifies ok.\n");
573 printf("INFO: Not checking signature due to key problems.\n");
575 } else if (!selfSigned
&& !invalid
&& issuerCert
) {
577 ver
= OurVerifySignedData(signedData
, issuerCert
);
578 if (ver
!= SECSuccess
) {
579 printf("PROBLEM: Verification of issuer's signature failed!\n");
581 printf("INFO: Issuer's signature verifies ok.\n");
584 printf("INFO: Not checking signature.\n");