checkcert.c
上传用户:lyxiangda
上传日期:2007-01-12
资源大小:3042k
文件大小:16k
源码类别:

CA认证

开发平台:

WINDOWS

  1. /*
  2.  * The contents of this file are subject to the Mozilla Public
  3.  * License Version 1.1 (the "License"); you may not use this file
  4.  * except in compliance with the License. You may obtain a copy of
  5.  * the License at http://www.mozilla.org/MPL/
  6.  * 
  7.  * Software distributed under the License is distributed on an "AS
  8.  * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
  9.  * implied. See the License for the specific language governing
  10.  * rights and limitations under the License.
  11.  * 
  12.  * The Original Code is the Netscape security libraries.
  13.  * 
  14.  * The Initial Developer of the Original Code is Netscape
  15.  * Communications Corporation.  Portions created by Netscape are 
  16.  * Copyright (C) 1994-2000 Netscape Communications Corporation.  All
  17.  * Rights Reserved.
  18.  * 
  19.  * Contributor(s):
  20.  * 
  21.  * Alternatively, the contents of this file may be used under the
  22.  * terms of the GNU General Public License Version 2 or later (the
  23.  * "GPL"), in which case the provisions of the GPL are applicable 
  24.  * instead of those above.  If you wish to allow use of your 
  25.  * version of this file only under the terms of the GPL and not to
  26.  * allow others to use your version of this file under the MPL,
  27.  * indicate your decision by deleting the provisions above and
  28.  * replace them with the notice and other provisions required by
  29.  * the GPL.  If you do not delete the provisions above, a recipient
  30.  * may use your version of this file under either the MPL or the
  31.  * GPL.
  32.  */
  33. #include "secutil.h"
  34. #include "plgetopt.h"
  35. #include "cert.h"
  36. #include "secoid.h"
  37. #include "cryptohi.h"
  38. /* maximum supported modulus length in bits (indicate problem if over this) */
  39. #define MAX_MODULUS (1024)
  40. static void Usage(char *progName)
  41. {
  42.     fprintf(stderr, "Usage: %s [aAvf] [certtocheck] [issuingcert]n",
  43.     progName);
  44.     fprintf(stderr, "%-20s Cert to check is base64 encodedn",
  45.     "-a");
  46.     fprintf(stderr, "%-20s Issuer's cert is base64 encodedn",
  47.     "-A");
  48.     fprintf(stderr, "%-20s Verbose (indicate decoding progress etc.)n",
  49.     "-v");
  50.     fprintf(stderr, "%-20s Force sanity checks even if pretty print fails.n",
  51.     "-f");
  52.     fprintf(stderr, "%-20s Define an output file to use (default is stdout)n",
  53.     "-o output");
  54.     fprintf(stderr, "%-20s Specify the input type (no default)n",
  55.     "-t type");
  56.     exit(-1);
  57. }
  58. /*
  59.  * Check integer field named fieldName, printing out results and
  60.  * returning the length of the integer in bits
  61.  */   
  62. static
  63. int checkInteger(SECItem *intItem, char *fieldName, int verbose) 
  64. {
  65.     int len, bitlen;
  66.     if (verbose) {
  67. printf("Checking %sn", fieldName);
  68.     }
  69.     
  70.     len = intItem->len;
  71.     
  72.     if (len && (intItem->data[0] & 0x80)) {
  73. printf("PROBLEM: %s is NEGATIVE 2's-complement integer.n",
  74.        fieldName);
  75.     }
  76.     
  77.     
  78.     /* calculate bit length and check for unnecessary leading zeros */
  79.     bitlen = len << 3;
  80.     if (len > 1 && intItem->data[0] == 0) {
  81. /* leading zero byte(s) */
  82. if (!(intItem->data[1] & 0x80)) {
  83.     printf("PROBLEM: %s has unneeded leading zeros.  Violates DER.n",
  84.    fieldName);
  85. }
  86. /* strip leading zeros in length calculation */
  87. {
  88.     int i=0;
  89.     while (bitlen > 8 && intItem->data[i] == 0) {
  90. bitlen -= 8;
  91. i++;
  92.     }
  93. }
  94.     }
  95.     return bitlen;
  96. }
  97. static
  98. void checkName(CERTName *n, char *fieldName, int verbose)
  99. {
  100.     char *v=0;
  101.     if (verbose) {
  102. printf("Checking %sn", fieldName);
  103.     }
  104.     
  105.     v = CERT_GetCountryName(n);
  106.     if (!v) {
  107. printf("PROBLEM: %s lacks Country Name (C)n",
  108.        fieldName);
  109.     }
  110.     PORT_Free(v);
  111.     
  112.     v = CERT_GetOrgName(n);
  113.     if (!v) {
  114. printf("PROBLEM: %s lacks Organization Name (O)n",
  115.        fieldName);
  116.     }
  117.     PORT_Free(v);
  118.     
  119.     v = CERT_GetOrgUnitName(n);
  120.     if (!v) {
  121. printf("WARNING: %s lacks Organization Unit Name (OU)n",
  122.        fieldName);
  123.     }
  124.     PORT_Free(v);
  125.     
  126.     v = CERT_GetCommonName(n);
  127.     if (!v) {
  128. printf("PROBLEM: %s lacks Common Name (CN)n",
  129.        fieldName);
  130.     }
  131.     PORT_Free(v);
  132. }
  133. /*
  134.  * Private version of verification that checks for agreement between
  135.  * signature algorithm oid (at the SignedData level) and oid in DigestInfo.
  136.  *
  137.  */
  138.      
  139.      
  140. /* Returns the tag for the hash algorithm in the given signature algorithm */
  141.      static
  142.      int hashAlg(int sigAlgTag) {
  143.  int rv;
  144.  switch(sigAlgTag) {
  145.    case SEC_OID_PKCS1_MD2_WITH_RSA_ENCRYPTION:
  146.      rv = SEC_OID_MD2;
  147.      break;
  148.    case SEC_OID_PKCS1_MD5_WITH_RSA_ENCRYPTION:
  149.      rv = SEC_OID_MD5;
  150.      break;
  151.    case SEC_OID_PKCS1_SHA1_WITH_RSA_ENCRYPTION:
  152.      rv = SEC_OID_SHA1;
  153.      break;
  154.    default:
  155.      rv = -1;
  156.  }
  157.  return rv;
  158.      }
  159. struct VFYContextStr {
  160.     int alg;
  161.     unsigned char digest[32];
  162.     void *hasher;
  163.     void (*begin)(void *);
  164.     void (*update)(void *, unsigned char*, unsigned);
  165.     SECStatus (*end)(void *, unsigned char*, unsigned int*, unsigned);
  166.     void (*destroy)(void *, PRBool);
  167. };
  168. static
  169. SECStatus
  170. OurVerifyData(unsigned char *buf, int len, SECKEYPublicKey *key,
  171.       SECItem *sig, SECAlgorithmID *sigAlgorithm)
  172. {
  173.     SECStatus rv;
  174.     VFYContext *cx;
  175.     SECOidData *sigAlgOid, *oiddata;
  176.     int sigAlgTag;
  177.     int hashAlgTag;
  178.     int showDigestOid=0;
  179.     
  180.     cx = VFY_CreateContext(key, sig, SECOID_GetAlgorithmTag(sigAlgorithm),
  181.    NULL);
  182.     if (cx == NULL)
  183. return SECFailure;
  184.     
  185.     sigAlgOid = SECOID_FindOID(&sigAlgorithm->algorithm);
  186.     if (sigAlgOid == 0)
  187. return SECFailure;
  188.     sigAlgTag = sigAlgOid->offset;
  189.     
  190.     hashAlgTag = hashAlg(sigAlgTag);
  191.     if (hashAlgTag == -1) {
  192. printf("PROBLEM: Unsupported Digest Algorithm in DigestInfo");
  193. showDigestOid = 1;
  194.     } else if (hashAlgTag != cx->alg) {
  195. printf("PROBLEM: Digest OID in DigestInfo is incompatible "
  196.        "with Signature Algorithmn");
  197. showDigestOid = 1;
  198.     } 
  199.     if (showDigestOid) {
  200. oiddata = SECOID_FindOIDByTag(cx->alg);
  201. if ( oiddata ) {
  202.     printf("PROBLEM: (cont) Digest OID is %sn", oiddata->desc);
  203. } else {
  204.     SECU_PrintAsHex(stdout,
  205.     &oiddata->oid, "PROBLEM: UNKNOWN OID", 0);
  206. }
  207.     }
  208.     
  209.     rv = VFY_Begin(cx);
  210.     if (rv == SECSuccess) {
  211. rv = VFY_Update(cx, buf, len);
  212. if (rv == SECSuccess)
  213.     rv = VFY_End(cx);
  214.     }
  215.     
  216.     VFY_DestroyContext(cx, PR_TRUE);
  217.     return rv;
  218. }
  219. static
  220. SECStatus
  221. OurVerifySignedData(CERTSignedData *sd, CERTCertificate *cert)
  222. {
  223.     SECItem sig;
  224.     SECKEYPublicKey *pubKey = 0;
  225.     SECStatus rv;
  226.     
  227.     /* check the certificate's validity */
  228.     rv = CERT_CertTimesValid(cert);
  229.     if ( rv ) {
  230. return(SECFailure);
  231.     }
  232.     
  233.     /* get cert's public key */
  234.     pubKey = CERT_ExtractPublicKey(cert);
  235.     if ( !pubKey ) {
  236. return(SECFailure);
  237.     }
  238.     
  239.     /* check the signature */
  240.     sig = sd->signature;
  241.     DER_ConvertBitString(&sig);
  242.     rv = OurVerifyData(sd->data.data, sd->data.len, pubKey, &sig,
  243.        &sd->signatureAlgorithm);
  244.     
  245.     SECKEY_DestroyPublicKey(pubKey);
  246.     
  247.     if ( rv ) {
  248. return(SECFailure);
  249.     }
  250.     
  251.     return(SECSuccess);
  252. }
  253. static
  254. CERTCertificate *createEmptyCertificate(void)
  255. {
  256.     PRArenaPool *arena = 0;
  257.     CERTCertificate *c = 0;
  258.     
  259.     arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
  260.     if ( !arena ) {
  261. return 0;
  262.     }
  263.     
  264.     
  265.     c = (CERTCertificate *) PORT_ArenaZAlloc(arena, sizeof(CERTCertificate));
  266.     
  267.     if (c) {
  268. c->referenceCount = 1;
  269. c->arena = arena;
  270.     } else {
  271. PORT_FreeArena(arena,PR_TRUE);
  272.     }
  273.     
  274.     return c;
  275. }    
  276. int main(int argc, char **argv)
  277. {
  278.     int rv, verbose=0, force=0;
  279.     int ascii=0, issuerAscii=0;
  280.     char *progName=0;
  281.     PRFileDesc *inFile=0, *issuerCertFile=0;
  282.     SECItem derCert, derIssuerCert;
  283.     PRArenaPool *arena=0;
  284.     CERTSignedData *signedData=0;
  285.     CERTCertificate *cert=0, *issuerCert=0;
  286.     SECKEYPublicKey *rsapubkey=0;
  287.     SECAlgorithmID md5WithRSAEncryption, md2WithRSAEncryption;
  288.     SECAlgorithmID sha1WithRSAEncryption, rsaEncryption;
  289.     SECItem spk;
  290.     int selfSigned=0;
  291.     int invalid=0;
  292.     char *inFileName = NULL, *issuerCertFileName = NULL;
  293.     PLOptState *optstate;
  294.     PLOptStatus status;
  295. PORT_Memset(&md5WithRSAEncryption, 0, sizeof(md5WithRSAEncryption));
  296. PORT_Memset(&md2WithRSAEncryption, 0, sizeof(md2WithRSAEncryption));
  297. PORT_Memset(&sha1WithRSAEncryption, 0, sizeof(sha1WithRSAEncryption));
  298. PORT_Memset(&rsaEncryption, 0, sizeof(rsaEncryption));
  299.     
  300.     progName = strrchr(argv[0], '/');
  301.     progName = progName ? progName+1 : argv[0];
  302.     
  303.     optstate = PL_CreateOptState(argc, argv, "aAvf");
  304.     while ((status = PL_GetNextOpt(optstate)) == PL_OPT_OK) {
  305. switch (optstate->option) {
  306.   case 'v':
  307.     verbose = 1;
  308.     break;
  309.     
  310.   case 'f':
  311.     force = 1;
  312.     break;
  313.     
  314.   case 'a':
  315.     ascii = 1;
  316.     break;
  317.     
  318.   case 'A':
  319.     issuerAscii = 1;
  320.     break;
  321.     
  322.   case '':
  323.     if (!inFileName)
  324. inFileName = PL_strdup(optstate->value);
  325.     else if (!issuerCertFileName)
  326. issuerCertFileName = PL_strdup(optstate->value);
  327.     else
  328. Usage(progName);
  329.     break;
  330. }
  331.     }
  332.     if (!inFileName || !issuerCertFileName || status == PL_OPT_BAD) {
  333. /* insufficient or excess args */
  334. Usage(progName);
  335.     }
  336.     
  337.     inFile = PR_Open(inFileName, PR_RDONLY, 0);
  338.     if (!inFile) {
  339. fprintf(stderr, "%s: unable to open "%s" for readingn",
  340.                  progName, inFileName);
  341. exit(1);
  342.     }
  343.     
  344.     issuerCertFile = PR_Open(issuerCertFileName, PR_RDONLY, 0);
  345.     if (!issuerCertFile) {
  346. fprintf(stderr, "%s: unable to open "%s" for readingn",
  347.                  progName, issuerCertFileName);
  348. exit(1);
  349.     }
  350.     
  351. if (SECU_ReadDERFromFile(&derCert, inFile, ascii) != SECSuccess) {
  352. printf("Couldn't read input certificate as DER binary or base64n");
  353. exit(1);
  354.     }
  355.     
  356.     arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
  357.     if (arena == 0) {
  358. fprintf(stderr,"%s: can't allocate scratch arena!", progName);
  359. exit(1);
  360.     }
  361.     
  362.     if (issuerCertFile) {
  363. CERTSignedData *issuerCertSD=0;
  364. if (SECU_ReadDERFromFile(&derIssuerCert, issuerCertFile, issuerAscii)
  365.     != SECSuccess) {
  366.     printf("Couldn't read issuer certificate as DER binary or base64.n");
  367.     exit(1);
  368. }
  369. issuerCertSD = (CERTSignedData *) PORT_ArenaZAlloc(arena,
  370. sizeof(CERTSignedData));
  371. if (!issuerCertSD) {
  372.     fprintf(stderr,"%s: can't allocate issuer signed data!", progName);
  373.     exit(1);
  374. }
  375. rv = SEC_ASN1DecodeItem(arena, issuerCertSD, CERT_SignedDataTemplate,
  376. &derIssuerCert);
  377. if (rv) {
  378.     fprintf(stderr, "%s: Issuer cert isn't X509 SIGNED Data?n",
  379.     progName);
  380.     exit(1);
  381. }
  382. issuerCert = createEmptyCertificate();
  383. if (!issuerCert) {
  384.     printf("%s: can't allocate space for issuer cert.", progName);
  385.     exit(1);
  386. }
  387. rv = SEC_ASN1DecodeItem(arena, issuerCert, CERT_CertificateTemplate,
  388.     &issuerCertSD->data);
  389. if (rv) {
  390.     printf("%s: Does not appear to be an X509 Certificate.n",
  391.    progName);
  392.     exit(1);
  393. }
  394.     }
  395.     
  396.     signedData = (CERTSignedData *) PORT_ArenaZAlloc(arena,sizeof(CERTSignedData));
  397.     if (!signedData) {
  398. fprintf(stderr,"%s: can't allocate signedData!", progName);
  399. exit(1);
  400.     }
  401.     
  402.     rv = SEC_ASN1DecodeItem(arena, signedData, CERT_SignedDataTemplate, 
  403.     &derCert);
  404.     if (rv) {
  405. fprintf(stderr, "%s: Does not appear to be X509 SIGNED Data.n",
  406. progName);
  407. exit(1);
  408.     }
  409.     
  410.     if (verbose) {
  411. printf("Decoded ok as X509 SIGNED data.n");
  412.     }
  413.     
  414.     cert = createEmptyCertificate();
  415.     if (!cert) {
  416. fprintf(stderr, "%s: can't allocate cert", progName);
  417. exit(1);
  418.     }
  419.     
  420.     rv = SEC_ASN1DecodeItem(arena, cert, CERT_CertificateTemplate, 
  421. &signedData->data);
  422.     if (rv) {
  423. fprintf(stderr, "%s: Does not appear to be an X509 Certificate.n",
  424. progName);
  425. exit(1);
  426.     }
  427.     
  428.     
  429.     if (verbose) {
  430. printf("Decoded ok as an X509 certificate.n");
  431.     }
  432.     
  433.     
  434.     rv = SECU_PrintSignedData(stdout, &derCert, "Certificate", 0,
  435.       SECU_PrintCertificate);
  436.     
  437.     if (rv) {
  438. fprintf(stderr, "%s: Unable to pretty print cert. Error: %dn",
  439. progName, PORT_GetError());
  440. if (!force) {
  441.     exit(1);
  442. }
  443.     }
  444.     
  445.     
  446.     /* Do various checks on the cert */
  447.     
  448.     printf("n");
  449.     
  450.     /* Check algorithms */
  451.     SECOID_SetAlgorithmID(arena, &md5WithRSAEncryption,
  452.        SEC_OID_PKCS1_MD5_WITH_RSA_ENCRYPTION, NULL);
  453.     
  454.     SECOID_SetAlgorithmID(arena, &md2WithRSAEncryption,
  455.        SEC_OID_PKCS1_MD2_WITH_RSA_ENCRYPTION, NULL);
  456.     
  457.     SECOID_SetAlgorithmID(arena, &sha1WithRSAEncryption,
  458.        SEC_OID_PKCS1_SHA1_WITH_RSA_ENCRYPTION, NULL);
  459.     SECOID_SetAlgorithmID(arena, &rsaEncryption,
  460.        SEC_OID_PKCS1_RSA_ENCRYPTION, NULL);
  461.     
  462.     {
  463. int isMD5RSA = (SECOID_CompareAlgorithmID(&cert->signature,
  464.        &md5WithRSAEncryption) == 0);
  465. int isMD2RSA = (SECOID_CompareAlgorithmID(&cert->signature,
  466.        &md2WithRSAEncryption) == 0);
  467. int isSHA1RSA = (SECOID_CompareAlgorithmID(&cert->signature,
  468.        &sha1WithRSAEncryption) == 0);
  469. if (verbose) {
  470.     printf("nDoing algorithm checks.n");
  471. }
  472. if (!(isMD5RSA || isMD2RSA || isSHA1RSA)) {
  473.     printf("PROBLEM: Signature not PKCS1 MD5, MD2, or SHA1 + RSA.n");
  474. } else if (!isMD5RSA) {
  475.     printf("WARNING: Signature not PKCS1 MD5 with RSA Encryptionn");
  476. }
  477. if (SECOID_CompareAlgorithmID(&cert->signature,
  478.    &signedData->signatureAlgorithm)) {
  479.     printf("PROBLEM: Algorithm in sig and certInfo don't match.n");
  480. }
  481.     }
  482.     
  483.     if (SECOID_CompareAlgorithmID(&cert->subjectPublicKeyInfo.algorithm,
  484.        &rsaEncryption)) {
  485. printf("PROBLEM: Public key algorithm is not PKCS1 RSA Encryption.n");
  486.     }
  487.     
  488.     /* Check further public key properties */
  489.     spk = cert->subjectPublicKeyInfo.subjectPublicKey;
  490.     DER_ConvertBitString(&spk);
  491.     
  492.     if (verbose) {
  493. printf("nsubjectPublicKey DERn");
  494. rv = DER_PrettyPrint(stdout, &spk, PR_FALSE);
  495. printf("n");
  496.     }
  497.     
  498.     rsapubkey = (SECKEYPublicKey *) 
  499.              PORT_ArenaZAlloc(arena,sizeof(SECKEYPublicKey));
  500.     if (!rsapubkey) {
  501. fprintf(stderr, "%s: rsapubkey allocation failed.n", progName);
  502. exit(1);
  503.     }
  504.     
  505.     rv = SEC_ASN1DecodeItem(arena, rsapubkey, SECKEY_RSAPublicKeyTemplate,
  506.     &spk);
  507.     if (rv) {
  508. printf("PROBLEM: subjectPublicKey is not a DER PKCS1 RSAPublicKey.n");
  509.     } else {
  510. int mlen;
  511. int pubexp;
  512. if (verbose) {
  513.     printf("Decoded RSA Public Key ok.  Doing key checks.n");
  514. }
  515. PORT_Assert(rsapubkey->keyType == rsaKey); /* XXX RSA */
  516. mlen = checkInteger(&rsapubkey->u.rsa.modulus, "Modulus", verbose);
  517. printf("INFO: Public Key modulus length in bits: %dn", mlen);
  518. if (mlen > MAX_MODULUS) {
  519.     printf("PROBLEM: Modulus length exceeds %d bits.n",
  520.    MAX_MODULUS);
  521. }
  522. if (mlen < 512) {
  523.     printf("WARNING: Short modulus.n");
  524. }
  525. if (mlen != (1 << (ffs(mlen)-1))) {
  526.     printf("WARNING: Unusual modulus length (not a power of two).n");
  527. }
  528. checkInteger(&rsapubkey->u.rsa.publicExponent, "Public Exponent",
  529.                      verbose);
  530. pubexp = DER_GetInteger(&rsapubkey->u.rsa.publicExponent);
  531. if (pubexp != 17 && pubexp != 3 && pubexp != 65537) {
  532.     printf("WARNING: Public exponent not any of: 3, 17, 65537n");
  533. }
  534.     }
  535.     
  536.     
  537.     /* Name checks */
  538.     checkName(&cert->issuer, "Issuer Name", verbose);
  539.     checkName(&cert->subject, "Subject Name", verbose);
  540.     
  541.     if (issuerCert) {
  542. SECComparison c =
  543.     CERT_CompareName(&cert->issuer, &issuerCert->subject);
  544. if (c) {
  545.          printf("PROBLEM: Issuer Name and Subject in Issuing Cert differn");
  546.         }
  547.     }
  548.     /* Check if self-signed */
  549.     selfSigned = (CERT_CompareName(&cert->issuer, &cert->subject) == 0);
  550.     if (selfSigned) {
  551. printf("INFO: Certificate is self signed.n");
  552.     } else {
  553. printf("INFO: Certificate is NOT self-signed.n");
  554.     }
  555.     
  556.     
  557.     /* Validity time check */
  558.     if (CERT_CertTimesValid(cert) == SECSuccess) {
  559. printf("INFO: Inside validity period of certificate.n");
  560.     } else {
  561. printf("PROBLEM: Not in validity period of certificate.n");
  562. invalid = 1;
  563.     }
  564.     
  565.     /* Signature check if self-signed */
  566.     if (selfSigned && !invalid) {
  567. if (rsapubkey->u.rsa.modulus.len) {
  568.     SECStatus ver;
  569.     if (verbose) {
  570. printf("Checking self signature.n");
  571.     }
  572.     ver = OurVerifySignedData(signedData, cert);
  573.     if (ver != SECSuccess) {
  574. printf("PROBLEM: Verification of self-signature failed!n");
  575.     } else {
  576. printf("INFO: Self-signature verifies ok.n");
  577.     }
  578. } else {
  579.     printf("INFO: Not checking signature due to key problems.n");
  580. }
  581.     } else if (!selfSigned && !invalid && issuerCert) {
  582. SECStatus ver;
  583. ver = OurVerifySignedData(signedData, issuerCert);
  584. if (ver != SECSuccess) {
  585.     printf("PROBLEM: Verification of issuer's signature failed!n");
  586. } else {
  587.     printf("INFO: Issuer's signature verifies ok.n");
  588. }
  589.     } else {
  590. printf("INFO: Not checking signature.n");
  591.     }
  592.     
  593.     return 0;    
  594. }