1 /* This Source Code Form is subject to the terms of the Mozilla Public
2  * License, v. 2.0. If a copy of the MPL was not distributed with this
3  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4 
5 #include "signtool.h"
6 #include "pk11func.h"
7 #include "certdb.h"
8 
9 static int num_trav_certs = 0;
10 static SECStatus cert_trav_callback(CERTCertificate *cert, SECItem *k,
11                                     void *data);
12 
13 /*********************************************************************
14  *
15  * L i s t C e r t s
16  */
17 int
ListCerts(char * key,int list_certs)18 ListCerts(char *key, int list_certs)
19 {
20     int failed = 0;
21     SECStatus rv;
22     CERTCertDBHandle *db;
23 
24     CERTCertificate *cert;
25     CERTVerifyLog errlog;
26 
27     errlog.arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
28     if (errlog.arena == NULL) {
29         out_of_memory();
30     }
31     errlog.head = NULL;
32     errlog.tail = NULL;
33     errlog.count = 0;
34 
35     db = CERT_GetDefaultCertDB();
36 
37     if (list_certs == 2) {
38         PR_fprintf(outputFD, "\nS Certificates\n");
39         PR_fprintf(outputFD, "- ------------\n");
40     } else {
41         PR_fprintf(outputFD, "\nObject signing certificates\n");
42         PR_fprintf(outputFD, "---------------------------------------\n");
43     }
44 
45     num_trav_certs = 0;
46 
47     /* Traverse ALL tokens in all slots, authenticating to them all */
48     rv = PK11_TraverseSlotCerts(cert_trav_callback, (void *)&list_certs,
49                                 &pwdata);
50 
51     if (rv) {
52         PR_fprintf(outputFD, "**Traverse of ALL slots & tokens failed**\n");
53         return -1;
54     }
55 
56     if (num_trav_certs == 0) {
57         PR_fprintf(outputFD,
58                    "You don't appear to have any object signing certificates.\n");
59     }
60 
61     if (list_certs == 2) {
62         PR_fprintf(outputFD, "- ------------\n");
63     } else {
64         PR_fprintf(outputFD, "---------------------------------------\n");
65     }
66 
67     if (list_certs == 1) {
68         PR_fprintf(outputFD,
69                    "For a list including CA's, use \"%s -L\"\n", PROGRAM_NAME);
70     }
71 
72     if (list_certs == 2) {
73         PR_fprintf(outputFD,
74                    "Certificates that can be used to sign objects have *'s to "
75                    "their left.\n");
76     }
77 
78     if (key) {
79         /* Do an analysis of the given cert */
80 
81         cert = PK11_FindCertFromNickname(key, &pwdata);
82 
83         if (cert) {
84             PR_fprintf(outputFD,
85                        "\nThe certificate with nickname \"%s\" was found:\n",
86                        cert->nickname);
87             PR_fprintf(outputFD, "\tsubject name: %s\n", cert->subjectName);
88             PR_fprintf(outputFD, "\tissuer name: %s\n", cert->issuerName);
89 
90             PR_fprintf(outputFD, "\n");
91 
92             rv = CERT_CertTimesValid(cert);
93             if (rv != SECSuccess) {
94                 PR_fprintf(outputFD, "**This certificate is expired**\n");
95             } else {
96                 PR_fprintf(outputFD, "This certificate is not expired.\n");
97             }
98 
99             rv = CERT_VerifyCert(db, cert, PR_TRUE,
100                                  certUsageObjectSigner, PR_Now(), &pwdata, &errlog);
101 
102             if (rv != SECSuccess) {
103                 failed = 1;
104                 if (errlog.count > 0) {
105                     PR_fprintf(outputFD,
106                                "**Certificate validation failed for the "
107                                "following reason(s):**\n");
108                 } else {
109                     PR_fprintf(outputFD, "**Certificate validation failed**");
110                 }
111             } else {
112                 PR_fprintf(outputFD, "This certificate is valid.\n");
113             }
114             displayVerifyLog(&errlog);
115 
116         } else {
117             failed = 1;
118             PR_fprintf(outputFD,
119                        "The certificate with nickname \"%s\" was NOT FOUND\n", key);
120         }
121     }
122 
123     if (errlog.arena != NULL) {
124         PORT_FreeArena(errlog.arena, PR_FALSE);
125     }
126 
127     if (failed) {
128         return -1;
129     }
130     return 0;
131 }
132 
133 /********************************************************************
134  *
135  * c e r t _ t r a v _ c a l l b a c k
136  */
137 static SECStatus
cert_trav_callback(CERTCertificate * cert,SECItem * k,void * data)138 cert_trav_callback(CERTCertificate *cert, SECItem *k, void *data)
139 {
140     int list_certs = 1;
141     char *name;
142 
143     if (data) {
144         list_certs = *((int *)data);
145     }
146 
147 #define LISTING_USER_SIGNING_CERTS (list_certs == 1)
148 #define LISTING_ALL_CERTS (list_certs == 2)
149 
150     name = cert->nickname;
151     if (name) {
152         int isSigningCert;
153 
154         isSigningCert = cert->nsCertType & NS_CERT_TYPE_OBJECT_SIGNING;
155         if (!isSigningCert && LISTING_USER_SIGNING_CERTS)
156             return (SECSuccess);
157 
158         /* Display this name or email address */
159         num_trav_certs++;
160 
161         if (LISTING_ALL_CERTS) {
162             PR_fprintf(outputFD, "%s ", isSigningCert ? "*" : " ");
163         }
164         PR_fprintf(outputFD, "%s\n", name);
165 
166         if (LISTING_USER_SIGNING_CERTS) {
167             int rv = SECFailure;
168             if (rv) {
169                 CERTCertificate *issuerCert;
170                 issuerCert = CERT_FindCertIssuer(cert, PR_Now(),
171                                                  certUsageObjectSigner);
172                 if (issuerCert) {
173                     if (issuerCert->nickname && issuerCert->nickname[0]) {
174                         PR_fprintf(outputFD, "    Issued by: %s\n",
175                                    issuerCert->nickname);
176                         rv = SECSuccess;
177                     }
178                     CERT_DestroyCertificate(issuerCert);
179                 }
180             }
181             if (rv && cert->issuerName && cert->issuerName[0]) {
182                 PR_fprintf(outputFD, "    Issued by: %s \n", cert->issuerName);
183             }
184             {
185                 char *expires;
186                 expires = DER_TimeChoiceDayToAscii(&cert->validity.notAfter);
187                 if (expires) {
188                     PR_fprintf(outputFD, "    Expires: %s\n", expires);
189                     PORT_Free(expires);
190                 }
191             }
192 
193             rv = CERT_VerifyCertNow(cert->dbhandle, cert,
194                                     PR_TRUE, certUsageObjectSigner, &pwdata);
195 
196             if (rv != SECSuccess) {
197                 rv = PORT_GetError();
198                 PR_fprintf(outputFD,
199                            "    ++ Error ++ THIS CERTIFICATE IS NOT VALID (%s)\n",
200                            secErrorString(rv));
201             }
202         }
203     }
204 
205     return (SECSuccess);
206 }
207