XRootD
Loading...
Searching...
No Matches
XrdCryptosslX509.cc
Go to the documentation of this file.
1/******************************************************************************/
2/* */
3/* X r d C r y p t o s s l X 5 0 9 . c c */
4/* */
5/* (c) 2005 G. Ganis , CERN */
6/* */
7/* This file is part of the XRootD software suite. */
8/* */
9/* XRootD is free software: you can redistribute it and/or modify it under */
10/* the terms of the GNU Lesser General Public License as published by the */
11/* Free Software Foundation, either version 3 of the License, or (at your */
12/* option) any later version. */
13/* */
14/* XRootD is distributed in the hope that it will be useful, but WITHOUT */
15/* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or */
16/* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public */
17/* License for more details. */
18/* */
19/* You should have received a copy of the GNU Lesser General Public License */
20/* along with XRootD in a file called COPYING.LESSER (LGPL license) and file */
21/* COPYING (GPL license). If not, see <http://www.gnu.org/licenses/>. */
22/* */
23/* The copyright holder's institutional names and contributor's names may not */
24/* be used to endorse or promote products derived from this software without */
25/* specific prior written permission of the institution or contributor. */
26/* */
27/******************************************************************************/
28
29/* ************************************************************************** */
30/* */
31/* OpenSSL implementation of XrdCryptoX509 */
32/* */
33/* ************************************************************************** */
38
39#include <openssl/pem.h>
40
41#include <cerrno>
42#include <memory>
43
44#include <fcntl.h>
45#include <unistd.h>
46#include <sys/types.h>
47#include <sys/stat.h>
48
49#define BIO_PRINT(b,c) \
50 BUF_MEM *bptr; \
51 BIO_get_mem_ptr(b, &bptr); \
52 if (bptr) { \
53 char *s = new char[bptr->length+1]; \
54 memcpy(s, bptr->data, bptr->length); \
55 s[bptr->length] = '\0'; \
56 PRINT(c << s); \
57 delete [] s; \
58 } else { \
59 PRINT("ERROR: "<<c<<" BIO internal buffer undefined!"); \
60 } \
61 if (b) BIO_free(b);
62
63const char *XrdCryptosslX509::cpxytype[5] = { "", "unknown", "RFC", "GSI3", "legacy" };
64
65//_____________________________________________________________________________
66XrdCryptosslX509::XrdCryptosslX509(const char *cf, const char *kf)
68{
69 // Constructor certificate from file 'cf'. If 'kf' is defined,
70 // complete the key of the certificate with the private key in kf.
71 EPNAME("X509::XrdCryptosslX509_file");
72
73 // Init private members
74 cert = 0; // The certificate object
75 notbefore = -1; // begin-validity time in secs since Epoch
76 notafter = -1; // end-validity time in secs since Epoch
77 subject = ""; // subject;
78 issuer = ""; // issuer;
79 subjecthash = ""; // hash of subject;
80 issuerhash = ""; // hash of issuer;
81 subjectoldhash = ""; // hash of subject (md5 algorithm);
82 issueroldhash = ""; // hash of issuer (md5 algorithm);
83 srcfile = ""; // source file;
84 bucket = 0; // bucket for serialization
85 pki = 0; // PKI of the certificate
86 pxytype = 0; // Proxy sub-type
87
88 // Make sure file name is defined;
89 if (!cf) {
90 DEBUG("file name undefined");
91 return;
92 }
93 // Make sure file exists;
94 struct stat st;
95 int fd = open(cf, O_RDONLY);
96
97 if (fd == -1) {
98 if (errno == ENOENT) {
99 DEBUG("file "<<cf<<" does not exist - do nothing");
100 } else {
101 DEBUG("cannot open file "<<cf<<" (errno: "<<errno<<")");
102 }
103 return;
104 }
105
106 if (fstat(fd, &st) != 0) {
107 DEBUG("cannot stat file "<<cf<<" (errno: "<<errno<<")");
108 close(fd);
109 return;
110 }
111 //
112 // Open file in read mode
113 FILE *fc = fdopen(fd, "r");
114 if (!fc) {
115 DEBUG("cannot fdopen file "<<cf<<" (errno: "<<errno<<")");
116 close(fd);
117 return;
118 }
119 //
120 // Read the content:
121 if (!PEM_read_X509(fc, &cert, 0, 0)) {
122 DEBUG("Unable to load certificate from file");
123 return;
124 } else {
125 DEBUG("certificate successfully loaded");
126 }
127 //
128 // Close the file
129 fclose(fc);
130 //
131 // Save source file name
132 srcfile = cf;
133
134 // Init some of the private members (the others upon need)
135 Subject();
136 Issuer();
137 CertType();
138
139 // Get the public key
140 EVP_PKEY *evpp = 0;
141 // Read the private key file, if specified
142 if (kf) {
143 int fd = open(kf, O_RDONLY);
144 if (fd == -1) {
145 DEBUG("cannot open file "<<kf<<" (errno: "<<errno<<")");
146 return;
147 }
148 if (fstat(fd, &st) == -1) {
149 DEBUG("cannot stat private key file "<<kf<<" (errno:"<<errno<<")");
150 close(fd);
151 return;
152 }
153 if (!S_ISREG(st.st_mode) || S_ISDIR(st.st_mode) ||
154 (st.st_mode & (S_IROTH | S_IWOTH)) != 0 ||
155 (st.st_mode & (S_IWGRP)) != 0) {
156 DEBUG("private key file "<<kf<<" has wrong permissions "<<
157 (st.st_mode & 0777) << " (should be at most 0640)");
158 close(fd);
159 return;
160 }
161 // Open file in read mode
162 FILE *fk = fdopen(fd, "r");
163 if (!fk) {
164 DEBUG("cannot open file "<<kf<<" (errno: "<<errno<<")");
165 close(fd);
166 return;
167 }
168 // This call fills the full key, i.e. also the public part (not really documented, though)
169 if ((evpp = PEM_read_PrivateKey(fk,0,0,0))) {
170 DEBUG("RSA key completed ");
171 // Test consistency
172 auto tmprsa = std::make_unique<XrdCryptosslRSA>(evpp, 1);
173 if (tmprsa->status == XrdCryptoRSA::kComplete) {
174 // Save it in pki
175 pki = tmprsa.release();
176 }
177 } else {
178 DEBUG("cannot read the key from file");
179 }
180 // Close the file
181 fclose(fk);
182 }
183 // If there were no private key or we did not manage to import it
184 // init pki with the partial key
185 if (!pki)
186 pki = new XrdCryptosslRSA(X509_get_pubkey(cert), 0);
187}
188
189//_____________________________________________________________________________
191{
192 // Constructor certificate from BIO 'bcer'
193 EPNAME("X509::XrdCryptosslX509_bio");
194
195 // Init private members
196 cert = 0; // The certificate object
197 notbefore = -1; // begin-validity time in secs since Epoch
198 notafter = -1; // end-validity time in secs since Epoch
199 subject = ""; // subject;
200 issuer = ""; // issuer;
201 subjecthash = ""; // hash of subject;
202 issuerhash = ""; // hash of issuer;
203 subjectoldhash = ""; // hash of subject (md5 algorithm);
204 issueroldhash = ""; // hash of issuer (md5 algorithm);
205 srcfile = ""; // source file;
206 bucket = 0; // bucket for serialization
207 pki = 0; // PKI of the certificate
208 pxytype = 0; // Proxy sub-type
209
210 // Make sure we got something;
211 if (!buck) {
212 DEBUG("got undefined opaque buffer");
213 return;
214 }
215
216 //
217 // Create a bio_mem to store the certificates
218 BIO *bmem = BIO_new(BIO_s_mem());
219 if (!bmem) {
220 DEBUG("unable to create BIO for memory operations");
221 return;
222 }
223
224 // Write data to BIO
225 int nw = BIO_write(bmem,(const void *)(buck->buffer),buck->size);
226 if (nw != buck->size) {
227 DEBUG("problems writing data to memory BIO (nw: "<<nw<<")");
228 return;
229 }
230
231 // Get certificate from BIO
232 if (!(cert = PEM_read_bio_X509(bmem,0,0,0))) {
233 DEBUG("unable to read certificate to memory BIO");
234 return;
235 }
236 //
237 // Free BIO
238 BIO_free(bmem);
239
240 //
241 // Init some of the private members (the others upon need)
242 Subject();
243 Issuer();
244 CertType();
245
246 // Get the public key
247 EVP_PKEY *evpp = X509_get_pubkey(cert);
248 //
249 if (evpp) {
250 // init pki with the partial key
251 if (!pki)
252 pki = new XrdCryptosslRSA(evpp, 0);
253 } else {
254 DEBUG("could not access the public key");
255 }
256}
257
258//_____________________________________________________________________________
260{
261 // Constructor: import X509 object
262 EPNAME("X509::XrdCryptosslX509_x509");
263
264 // Init private members
265 cert = 0; // The certificate object
266 notbefore = -1; // begin-validity time in secs since Epoch
267 notafter = -1; // end-validity time in secs since Epoch
268 subject = ""; // subject;
269 issuer = ""; // issuer;
270 subjecthash = ""; // hash of subject;
271 issuerhash = ""; // hash of issuer;
272 subjectoldhash = ""; // hash of subject (md5 algorithm);
273 issueroldhash = ""; // hash of issuer (md5 algorithm);
274 srcfile = ""; // source file;
275 bucket = 0; // bucket for serialization
276 pki = 0; // PKI of the certificate
277 pxytype = 0; // Proxy sub-type
278
279 // Make sure we got something;
280 if (!xc) {
281 DEBUG("got undefined X509 object");
282 return;
283 }
284
285 // Set certificate
286 cert = xc;
287
288 //
289 // Init some of the private members (the others upon need)
290 Subject();
291 Issuer();
292 CertType();
293
294 // Get the public key
295 EVP_PKEY *evpp = X509_get_pubkey(cert);
296 //
297 if (evpp) {
298 // init pki with the partial key
299 if (!pki)
300 pki = new XrdCryptosslRSA(evpp, 0);
301 } else {
302 DEBUG("could not access the public key");
303 }
304}
305
306//_____________________________________________________________________________
308{
309 // Destructor
310
311 // Cleanup certificate
312 if (cert) X509_free(cert);
313 // Cleanup key
314 if (pki) delete pki;
315}
316
317//_____________________________________________________________________________
318void XrdCryptosslX509::CertType()
319{
320 // Determine the certificate type
321 // Check the type of this certificate
322 EPNAME("X509::CertType");
323
324 // Make sure we got something to look for
325 if (!cert) {
326 PRINT("ERROR: certificate is not initialized");
327 return;
328 }
329
330 // Default for an initialized certificate
331 type = kEEC;
332
333 // Are there any extension?
334 int numext = X509_get_ext_count(cert);
335 if (numext <= 0) {
336 DEBUG("certificate has got no extensions");
337 return;
338 }
339 TRACE(ALL,"certificate has "<<numext<<" extensions");
340
341 bool done = 0;
342 // Check the extensions
343#if OPENSSL_VERSION_NUMBER < 0x40000000L
344 X509_EXTENSION *ext = 0;
345#else
346 const X509_EXTENSION *ext = 0;
347#endif
348 int idx = -1;
349
350 // For CAs we are looking for a "basicConstraints"
351 int crit;
352 BASIC_CONSTRAINTS *bc = 0;
353 if ((bc = (BASIC_CONSTRAINTS *)X509_get_ext_d2i(cert, NID_basic_constraints, &crit, &idx)) &&
354 bc->ca) {
355 type = kCA;
356 DEBUG("CA certificate");
357 done = 1;
358 }
359 if (bc) BASIC_CONSTRAINTS_free(bc);
360 if (done) return;
361
362 // Is this a proxy?
363 idx = -1;
364 // Proxy names
365 XrdOucString common(subject, 0, subject.rfind("/CN=") - 1);
366 bool pxyname = 0;
367 if (issuer == common) {
368 pxyname = 1;
369 pxytype = 1;
370 }
371
372 if (pxyname) {
373 type = kUnknown;
374 if ((idx = X509_get_ext_by_NID(cert, NID_proxyCertInfo,-1)) == -1) {
375 int xcp = -1;
376 XrdOucString emsg;
377 if ((xcp = XrdCryptosslX509CheckProxy3(this, emsg)) == 0) {
378 type = kProxy;
379 pxytype = 3;
380 DEBUG("Found GSI 3 proxyCertInfo extension");
381 } else if (xcp == -1) {
382 PRINT("ERROR: "<<emsg);
383 }
384 } else {
385 if ((ext = X509_get_ext(cert,idx)) == 0) {
386 PRINT("ERROR: could not get proxyCertInfo extension");
387 }
388 }
389 }
390 if (ext) {
391 // RFC compliant or GSI 3 proxy
392 if (X509_EXTENSION_get_critical(ext)) {
393 PROXY_CERT_INFO_EXTENSION *pci = (PROXY_CERT_INFO_EXTENSION *)X509V3_EXT_d2i(ext);
394 if (pci != 0) {
395 if ((pci->proxyPolicy) != 0) {
396 if ((pci->proxyPolicy->policyLanguage) != 0) {
397 type = kProxy;
398 done = 1;
399 pxytype = 2;
400 DEBUG("Found RFC 382{0,1}compliant proxyCertInfo extension");
401 if (X509_get_ext_by_NID(cert, NID_proxyCertInfo, idx) != -1) {
402 PRINT("WARNING: multiple proxyCertInfo extensions found: taking the first");
403 }
404 } else {
405 PRINT("ERROR: accessing policy language from proxyCertInfo extension");
406 }
407 } else {
408 PRINT("ERROR: accessing policy from proxyCertInfo extension");
409 }
410 PROXY_CERT_INFO_EXTENSION_free(pci);
411 } else {
412 PRINT("ERROR: proxyCertInfo conversion error");
413 }
414 } else {
415 PRINT("ERROR: proxyCertInfo not flagged as critical");
416 }
417 }
418 if (!pxyname || done) return;
419
420 // Check if GSI 2 legacy proxy
421 XrdOucString lastcn(subject, subject.rfind("/CN=") + 4, -1);
422 if (lastcn == "proxy" || lastcn == "limited proxy") {
423 pxytype = 4;
424 type = kProxy;
425 }
426
427 // We are done
428 return;
429}
430
431//_____________________________________________________________________________
433{
434 // SetPKI:
435 // if newpki is null does nothing
436 // if newpki contains a consistent private & public key we take ownership
437 // so that this->PKI()->status will be kComplete.
438 // otherwise, newpki is not consistent:
439 // if the previous PKI() was null or was already kComplete it is and reset
440 // so that this->PKI()->status will be kInvalid.
441
442 if (!newpki) return;
443
444 auto tmprsa = std::make_unique<XrdCryptosslRSA>((EVP_PKEY*)newpki, 1);
445 if (!pki || pki->status == XrdCryptoRSA::kComplete ||
446 tmprsa->status == XrdCryptoRSA::kComplete) {
447 // Cleanup any existing key first
448 if (pki)
449 delete pki;
450
451 // Set PKI
452 pki = tmprsa.release();
453 }
454}
455
456//_____________________________________________________________________________
458{
459 // Begin-validity time in secs since Epoch
460
461 // If we do not have it already, try extraction
462 if (notbefore < 0) {
463 // Make sure we have a certificate
464 if (cert)
465 // Extract UTC time in secs from Epoch
466 notbefore = XrdCryptosslASN1toUTC(X509_get_notBefore(cert));
467 }
468 // return what we have
469 return notbefore;
470}
471
472//_____________________________________________________________________________
474{
475 // End-validity time in secs since Epoch
476
477 // If we do not have it already, try extraction
478 if (notafter < 0) {
479 // Make sure we have a certificate
480 if (cert)
481 // Extract UTC time in secs from Epoch
482 notafter = XrdCryptosslASN1toUTC(X509_get_notAfter(cert));
483 }
484 // return what we have
485 return notafter;
486}
487
488//_____________________________________________________________________________
490{
491 // Return subject name
492 EPNAME("X509::Subject");
493
494 // If we do not have it already, try extraction
495 if (subject.length() <= 0) {
496
497 // Make sure we have a certificate
498 if (!cert) {
499 DEBUG("WARNING: no certificate available - cannot extract subject name");
500 return (const char *)0;
501 }
502
503 // Extract subject name
504 XrdCryptosslNameOneLine(X509_get_subject_name(cert), subject);
505 }
506
507 // return what we have
508 return (subject.length() > 0) ? subject.c_str() : (const char *)0;
509}
510
511//_____________________________________________________________________________
513{
514 // Return issuer name
515 EPNAME("X509::Issuer");
516
517 // If we do not have it already, try extraction
518 if (issuer.length() <= 0) {
519
520 // Make sure we have a certificate
521 if (!cert) {
522 DEBUG("WARNING: no certificate available - cannot extract issuer name");
523 return (const char *)0;
524 }
525
526 // Extract issuer name
527 XrdCryptosslNameOneLine(X509_get_issuer_name(cert), issuer);
528 }
529
530 // return what we have
531 return (issuer.length() > 0) ? issuer.c_str() : (const char *)0;
532}
533
534//_____________________________________________________________________________
536{
537 // Return hash of issuer name
538 // Use default algorithm (X509_NAME_hash) for alg = 0, old algorithm
539 // (for v>=1.0.0) when alg = 1
540 EPNAME("X509::IssuerHash");
541
542 if (alg == 1) {
543 // md5 based
544 if (issueroldhash.length() <= 0) {
545 // Make sure we have a certificate
546 if (cert) {
547 char chash[30] = {0};
548 snprintf(chash, sizeof(chash),
549 "%08lx.0",X509_NAME_hash_old(X509_get_issuer_name(cert)));
550 issueroldhash = chash;
551 } else {
552 DEBUG("WARNING: no certificate available - cannot extract issuer hash (md5)");
553 }
554 }
555 // return what we have
556 return (issueroldhash.length() > 0) ? issueroldhash.c_str() : (const char *)0;
557 }
558
559 // If we do not have it already, try extraction
560 if (issuerhash.length() <= 0) {
561
562 // Make sure we have a certificate
563 if (cert) {
564 char chash[30] = {0};
565 snprintf(chash, sizeof(chash),
566 "%08lx.0",X509_NAME_hash(X509_get_issuer_name(cert)));
567 issuerhash = chash;
568 } else {
569 DEBUG("WARNING: no certificate available - cannot extract issuer hash (default)");
570 }
571 }
572
573 // return what we have
574 return (issuerhash.length() > 0) ? issuerhash.c_str() : (const char *)0;
575}
576
577//_____________________________________________________________________________
579{
580 // Return hash of subject name
581 // Use default algorithm (X509_NAME_hash) for alg = 0, old algorithm
582 // (for v>=1.0.0) when alg = 1
583 EPNAME("X509::SubjectHash");
584
585 if (alg == 1) {
586 // md5 based
587 if (subjectoldhash.length() <= 0) {
588 // Make sure we have a certificate
589 if (cert) {
590 char chash[30] = {0};
591 snprintf(chash, sizeof(chash),
592 "%08lx.0",X509_NAME_hash_old(X509_get_subject_name(cert)));
593 subjectoldhash = chash;
594 } else {
595 DEBUG("WARNING: no certificate available - cannot extract subject hash (md5)");
596 }
597 }
598 // return what we have
599 return (subjectoldhash.length() > 0) ? subjectoldhash.c_str() : (const char *)0;
600 }
601
602 // If we do not have it already, try extraction
603 if (subjecthash.length() <= 0) {
604
605 // Make sure we have a certificate
606 if (cert) {
607 char chash[30] = {0};
608 snprintf(chash, sizeof(chash),
609 "%08lx.0",X509_NAME_hash(X509_get_subject_name(cert)));
610 subjecthash = chash;
611 } else {
612 DEBUG("WARNING: no certificate available - cannot extract subject hash (default)");
613 }
614 }
615
616 // return what we have
617 return (subjecthash.length() > 0) ? subjecthash.c_str() : (const char *)0;
618}
619
620//_____________________________________________________________________________
622{
623 // Return serial number as a kXR_int64
624
625 kXR_int64 sernum = -1;
626 if (cert && X509_get_serialNumber(cert)) {
627 BIGNUM *bn = BN_new();
628 ASN1_INTEGER_to_BN(X509_get_serialNumber(cert), bn);
629 char *sn = BN_bn2dec(bn);
630 sernum = strtoll(sn, 0, 10);
631 BN_free(bn);
632 OPENSSL_free(sn);
633 }
634
635 return sernum;
636}
637
638//_____________________________________________________________________________
640{
641 // Return serial number as a hex string
642
643 XrdOucString sernum;
644 if (cert && X509_get_serialNumber(cert)) {
645 BIGNUM *bn = BN_new();
646 ASN1_INTEGER_to_BN(X509_get_serialNumber(cert), bn);
647 char *sn = BN_bn2hex(bn);
648 sernum = sn;
649 BN_free(bn);
650 OPENSSL_free(sn);
651 }
652
653 return sernum;
654}
655
656//_____________________________________________________________________________
658{
659 // Return pointer to extension with OID oid, if any, in
660 // opaque form
661 EPNAME("X509::GetExtension");
662 XrdCryptoX509data ext = 0;
663
664 // Make sure we got something to look for
665 if (!oid) {
666 DEBUG("OID string not defined");
667 return ext;
668 }
669
670 // Make sure we got something to look for
671 if (!cert) {
672 DEBUG("certificate is not initialized");
673 return ext;
674 }
675
676 // Are there any extension?
677 int numext = X509_get_ext_count(cert);
678 if (numext <= 0) {
679 DEBUG("certificate has got no extensions");
680 return ext;
681 }
682 DEBUG("certificate has "<<numext<<" extensions");
683
684 // If the string is the Standard Name of a known extension check
685 // searche the corresponding NID
686 int nid = OBJ_sn2nid(oid);
687 bool usenid = (nid > 0);
688
689 // Loop to identify the one we would like
690 int i = 0;
691#if OPENSSL_VERSION_NUMBER < 0x40000000L
692 X509_EXTENSION *wext = 0;
693#else
694 const X509_EXTENSION *wext = 0;
695#endif
696 for (i = 0; i< numext; i++) {
697 wext = X509_get_ext(cert, i);
698 if (usenid) {
699 int enid = OBJ_obj2nid(X509_EXTENSION_get_object(wext));
700 if (enid == nid)
701 break;
702 } else {
703 // Try matching of the text
704 char s[256];
705 OBJ_obj2txt(s, sizeof(s), X509_EXTENSION_get_object(wext), 1);
706 if (!strcmp(s, oid))
707 break;
708 }
709 // Do not free the extension: its owned by the certificate
710 wext = 0;
711 }
712
713 // We are done if nothing was found
714 if (!wext) {
715 DEBUG("Extension "<<oid<<" not found");
716 return ext;
717 }
718
719 // We are done
720 return (XrdCryptoX509data)wext;
721}
722
723//_____________________________________________________________________________
725{
726 // Export in form of bucket
727 EPNAME("X509::Export");
728
729 // If we have already done it, return the previous result
730 if (bucket) {
731 DEBUG("serialization already performed:"
732 " return previous result ("<<bucket->size<<" bytes)");
733 return bucket;
734 }
735
736 // Make sure we got something to export
737 if (!cert) {
738 DEBUG("certificate is not initialized");
739 return 0;
740 }
741
742 //
743 // Now we create a bio_mem to serialize the certificate
744 BIO *bmem = BIO_new(BIO_s_mem());
745 if (!bmem) {
746 DEBUG("unable to create BIO for memory operations");
747 return 0;
748 }
749
750 // Write certificate to BIO
751 if (!PEM_write_bio_X509(bmem, cert)) {
752 DEBUG("unable to write certificate to memory BIO");
753 return 0;
754 }
755
756 // Extract pointer to BIO data and length of segment
757 char *bdata = 0;
758 int blen = BIO_get_mem_data(bmem, &bdata);
759 DEBUG("BIO data: "<<blen<<" bytes at 0x"<<(int *)bdata);
760
761 // create the bucket now
762 bucket = new XrdSutBucket(0,0,kXRS_x509);
763 if (bucket) {
764 // Fill bucket
765 bucket->SetBuf(bdata, blen);
766 DEBUG("result of serialization: "<<bucket->size<<" bytes");
767 } else {
768 DEBUG("unable to create bucket for serialized format");
769 BIO_free(bmem);
770 return 0;
771 }
772 //
773 // Free BIO
774 BIO_free(bmem);
775 //
776 // We are done
777 return bucket;
778}
779
780//_____________________________________________________________________________
782{
783 // Verify certificate signature with pub key of ref cert
784 EPNAME("X509::Verify");
785
786 // We must have been initialized
787 if (!cert)
788 return 0;
789
790 // We must have something to check with
791 X509 *r = ref ? (X509 *)(ref->Opaque()) : 0;
792 EVP_PKEY *rk = r ? X509_get_pubkey(r) : 0;
793 if (!rk)
794 return 0;
795
796 // Ok: we can verify
797 int rc = X509_verify(cert, rk);
798 EVP_PKEY_free(rk);
799 if (rc <= 0) {
800 if (rc == 0) {
801 // Signatures are not OK
802 DEBUG("signature not OK");
803 } else {
804 // General failure
805 DEBUG("could not verify signature");
806 }
807 return 0;
808 }
809 // Success
810 return 1;
811}
812
813//____________________________________________________________________________
815{
816 // Dump our extensions, if any
817 // Returns -1 on failure, 0 on success
818 EPNAME("DumpExtensions");
819
820 int rc = -1;
821 // Point to the cerificate
822 X509 *xpi = (X509 *) Opaque();
823
824 // Make sure we got the right inputs
825 if (!xpi) {
826 PRINT("we are empty! Do nothing");
827 return rc;
828 }
829
830 rc = 1;
831 // Go through the extensions
832#if OPENSSL_VERSION_NUMBER < 0x40000000L
833 X509_EXTENSION *xpiext = 0;
834#else
835 const X509_EXTENSION *xpiext = 0;
836#endif
837 int npiext = X509_get_ext_count(xpi);
838 PRINT("found "<<npiext<<" extensions ");
839 int i = 0;
840 for (i = 0; i< npiext; i++) {
841 xpiext = X509_get_ext(xpi, i);
842 char s[256];
843 OBJ_obj2txt(s, sizeof(s), X509_EXTENSION_get_object(xpiext), 1);
844 int crit = X509_EXTENSION_get_critical(xpiext);
845 // Notify what we found
846 PRINT(i << ": found extension '"<<s<<"', critical: " << crit);
847 // Dump its content
848 rc = 0;
849 const unsigned char *pp = ASN1_STRING_get0_data(X509_EXTENSION_get_data(xpiext));
850 long length = ASN1_STRING_length(X509_EXTENSION_get_data(xpiext));
851 int ret = FillUnknownExt(&pp, length, dumpunknown);
852 PRINT("ret: " << ret);
853 }
854
855 // Done
856 return rc;
857}
858
859//____________________________________________________________________________
860int XrdCryptosslX509::FillUnknownExt(const unsigned char **pp, long length, bool dump)
861{
862 // Do the actual filling of the bio; can be called recursevely
863 EPNAME("FillUnknownExt");
864
865 const unsigned char *p,*ep,*tot,*op,*opp;
866 long len;
867 int tag, xclass, ret = 0;
868 int nl,hl,j,r;
869 ASN1_OBJECT *o = 0;
870 ASN1_OCTET_STRING *os = 0;
871 /* ASN1_BMPSTRING *bmp=NULL;*/
872 int dump_indent = 6;
873 int depth = 0;
874 int indent = 0;
875
876 p = *pp;
877 tot = p + length;
878 op = p - 1;
879 while ((p < tot) && (op < p)) {
880 op = p;
881 j = ASN1_get_object(&p, &len, &tag, &xclass, length);
882#ifdef LINT
883 j = j;
884#endif
885 if (j & 0x80) {
886 if (dump) PRINT("ERROR: error in encoding");
887 ret = 0;
888 goto end;
889 }
890 hl = (p-op);
891 length -= hl;
892 /* if j == 0x21 it is a constructed indefinite length object */
893
894 if (j != (V_ASN1_CONSTRUCTED | 1)) {
895 if (dump) PRINT("PRIM: d="<<depth<<" hl="<<hl<<" l="<<len);
896 } else {
897 if (dump) PRINT("CONST: d="<<depth<<" hl="<<hl<<" l=inf ");
898 }
899 if (!Asn1PrintInfo(tag, xclass, j, (indent) ? depth : 0))
900 goto end;
901 if (j & V_ASN1_CONSTRUCTED) {
902 ep = p + len;
903 if (dump) PRINT(" ");
904 if (len > length) {
905 if (dump) PRINT("ERROR:CONST: length is greater than " <<length);
906 ret=0;
907 goto end;
908 }
909 if ((j == 0x21) && (len == 0)) {
910 for (;;) {
911 r = FillUnknownExt(&p, (long)(tot-p), dump);
912 if (r == 0) {
913 ret = 0;
914 goto end;
915 }
916 if ((r == 2) || (p >= tot))
917 break;
918 }
919 } else {
920 while (p < ep) {
921 r = FillUnknownExt(&p, (long)len, dump);
922 if (r == 0) {
923 ret = 0;
924 goto end;
925 }
926 }
927 }
928 } else if (xclass != 0) {
929 p += len;
930 if (dump) PRINT(" ");
931 } else {
932 nl = 0;
933 if ((tag == V_ASN1_PRINTABLESTRING) ||
934 (tag == V_ASN1_T61STRING) ||
935 (tag == V_ASN1_IA5STRING) ||
936 (tag == V_ASN1_VISIBLESTRING) ||
937 (tag == V_ASN1_NUMERICSTRING) ||
938 (tag == V_ASN1_UTF8STRING) ||
939 (tag == V_ASN1_UTCTIME) ||
940 (tag == V_ASN1_GENERALIZEDTIME)) {
941 if (len > 0) {
942 char *s = new char[len + 1];
943 memcpy(s, p, len);
944 s[len] = 0;
945 if (dump) PRINT("GENERIC:" << s <<" (len: "<<(int)len<<")");
946 delete [] s;
947 } else {
948 if (dump) PRINT("GENERIC: (len: "<<(int)len<<")");
949 }
950 } else if (tag == V_ASN1_OBJECT) {
951 opp = op;
952 if (d2i_ASN1_OBJECT(&o, &opp, len+hl)) {
953 BIO *mem = BIO_new(BIO_s_mem());
954 i2a_ASN1_OBJECT(mem, o);
955 XrdOucString objstr;
956 if (dump) { BIO_PRINT(mem, "AOBJ:"); }
957 } else {
958 if (dump) PRINT("ERROR:AOBJ: BAD OBJECT");
959 }
960 } else if (tag == V_ASN1_BOOLEAN) {
961 if (len != 1) {
962 if (dump) PRINT("ERROR:BOOL: Bad boolean");
963 goto end;
964 }
965 if (dump) PRINT("BOOL:"<< p[0]);
966 } else if (tag == V_ASN1_BMPSTRING) {
967 /* do the BMP thang */
968 } else if (tag == V_ASN1_OCTET_STRING) {
969 int i, printable = 1;
970 opp = op;
971 os = d2i_ASN1_OCTET_STRING(0, &opp, len + hl);
972 if (os && ASN1_STRING_length(os) > 0) {
973 opp = ASN1_STRING_get0_data(os);
974 /* testing whether the octet string is * printable */
975 for (i=0; i < ASN1_STRING_length(os); i++) {
976 if (( (opp[i] < ' ') && (opp[i] != '\n') &&
977 (opp[i] != '\r') && (opp[i] != '\t')) || (opp[i] > '~')) {
978 printable = 0;
979 break;
980 }
981 }
982 if (printable) {
983 /* printable string */
984 char *s = new char[ASN1_STRING_length(os) + 1];
985 memcpy(s, opp, ASN1_STRING_length(os));
986 s[ASN1_STRING_length(os)] = 0;
987 if (dump) PRINT("OBJS:" << s << " (len: " << ASN1_STRING_length(os) << ")");
988 delete [] s;
989 } else {
990 /* print the normal dump */
991 if (!nl) PRINT("OBJS:");
992 BIO *mem = BIO_new(BIO_s_mem());
993 if (BIO_dump_indent(mem, (const char *)opp, ASN1_STRING_length(os), dump_indent) <= 0) {
994 if (dump) PRINT("ERROR:OBJS: problems dumping to BIO");
995 BIO_free(mem);
996 goto end;
997 }
998 if (dump) { BIO_PRINT(mem, "OBJS:"); }
999 nl = 1;
1000 }
1001 }
1002 if (os) {
1003 ASN1_OCTET_STRING_free(os);
1004 os = 0;
1005 }
1006 } else if (tag == V_ASN1_INTEGER) {
1007 ASN1_INTEGER *bs;
1008 int i;
1009
1010 opp = op;
1011 bs = d2i_ASN1_INTEGER(0, &opp, len+hl);
1012 if (bs) {
1013 if (dump) PRINT("AINT:");
1014 if (ASN1_STRING_type(bs) == V_ASN1_NEG_INTEGER)
1015 if (dump) PRINT("-");
1016 BIO *mem = BIO_new(BIO_s_mem());
1017 for (i = 0; i < ASN1_STRING_length(bs); i++) {
1018 if (BIO_printf(mem, "%02X", ASN1_STRING_get0_data(bs)[i]) <= 0) {
1019 if (dump) PRINT("ERROR:AINT: problems printf-ing to BIO");
1020 BIO_free(mem);
1021 goto end;
1022 }
1023 }
1024 if (dump) { BIO_PRINT(mem, "AINT:"); }
1025 if (ASN1_STRING_length(bs) == 0) PRINT("00");
1026 } else {
1027 if (dump) PRINT("ERROR:AINT: BAD INTEGER");
1028 }
1029 ASN1_INTEGER_free(bs);
1030 } else if (tag == V_ASN1_ENUMERATED) {
1031 ASN1_ENUMERATED *bs;
1032 int i;
1033
1034 opp = op;
1035 bs = d2i_ASN1_ENUMERATED(0, &opp, len+hl);
1036 if (bs) {
1037 if (dump) PRINT("AENU:");
1038 if (ASN1_STRING_type(bs) == V_ASN1_NEG_ENUMERATED)
1039 if (dump) PRINT("-");
1040 BIO *mem = BIO_new(BIO_s_mem());
1041 for (i = 0; i < ASN1_STRING_length(bs); i++) {
1042 if (BIO_printf(mem, "%02X", ASN1_STRING_get0_data(bs)[i]) <= 0) {
1043 if (dump) PRINT("ERROR:AENU: problems printf-ing to BIO");
1044 BIO_free(mem);
1045 goto end;
1046 }
1047 }
1048 if (dump) { BIO_PRINT(mem, "AENU:"); }
1049 if (ASN1_STRING_length(bs) == 0) PRINT("00");
1050 } else {
1051 if (dump) PRINT("ERROR:AENU: BAD ENUMERATED");
1052 }
1053 ASN1_ENUMERATED_free(bs);
1054 }
1055
1056 if (!nl && dump) PRINT(" ");
1057
1058 p += len;
1059 if ((tag == V_ASN1_EOC) && (xclass == 0)) {
1060 ret = 2; /* End of sequence */
1061 goto end;
1062 }
1063 }
1064 length -= len;
1065 }
1066 ret = 1;
1067end:
1068 if (o) ASN1_OBJECT_free(o);
1069 if (os) ASN1_OCTET_STRING_free(os);
1070 *pp = p;
1071 if (dump) PRINT("ret: "<<ret);
1072
1073 return ret;
1074}
1075
1076//____________________________________________________________________________
1077int XrdCryptosslX509::Asn1PrintInfo(int tag, int xclass, int constructed, int indent)
1078{
1079 // Print the BIO content
1080 EPNAME("Asn1PrintInfo");
1081
1082 static const char fmt[]="%-18s";
1083 static const char fmt2[]="%2d %-15s";
1084 char str[128];
1085 const char *p, *p2 = 0;
1086
1087 BIO *bp = BIO_new(BIO_s_mem());
1088 if (constructed & V_ASN1_CONSTRUCTED)
1089 p = "cons: ";
1090 else
1091 p = "prim: ";
1092 if (BIO_write(bp, p, 6) < 6)
1093 goto err;
1094 BIO_indent(bp, indent, 128);
1095
1096 p = str;
1097 if ((xclass & V_ASN1_PRIVATE) == V_ASN1_PRIVATE)
1098 BIO_snprintf(str,sizeof str,"priv [ %d ] ",tag);
1099 else if ((xclass & V_ASN1_CONTEXT_SPECIFIC) == V_ASN1_CONTEXT_SPECIFIC)
1100 BIO_snprintf(str,sizeof str,"cont [ %d ]",tag);
1101 else if ((xclass & V_ASN1_APPLICATION) == V_ASN1_APPLICATION)
1102 BIO_snprintf(str,sizeof str,"appl [ %d ]",tag);
1103 else if (tag > 30)
1104 BIO_snprintf(str,sizeof str,"<ASN1 %d>",tag);
1105 else
1106 p = ASN1_tag2str(tag);
1107
1108 if (p2) {
1109 if (BIO_printf(bp,fmt2,tag,p2) <= 0)
1110 goto err;
1111 } else {
1112 if (BIO_printf(bp, fmt, p) <= 0)
1113 goto err;
1114 }
1115 BIO_PRINT(bp, "A1PI:");
1116 return(1);
1117err:
1118 BIO_free(bp);
1119 return(0);
1120}
1121
1122//____________________________________________________________________________
1123bool XrdCryptosslX509::MatchesSAN(const char *fqdn, bool &hasSAN)
1124{
1125 EPNAME("MatchesSAN");
1126
1127 // Statically allocated array for hostname lengths. RFC1035 limits
1128 // valid lengths to 255 characters.
1129 char san_fqdn[256];
1130
1131 // Assume we have no SAN extension. Failure may allow the caller to try
1132 // using the common name before giving up.
1133 hasSAN = false;
1134
1135 GENERAL_NAMES *gens = static_cast<GENERAL_NAMES *>(X509_get_ext_d2i(cert,
1136 NID_subject_alt_name, NULL, NULL));
1137 if (!gens)
1138 return false;
1139
1140 // Only an EEC is usable as a host certificate.
1141 if (type != kEEC)
1142 return false;
1143
1144 // All failures are under the notion that we have a SAN extension.
1145 hasSAN = true;
1146
1147 if (!fqdn)
1148 return false;
1149
1150 bool success = false;
1151 for (int idx = 0; idx < sk_GENERAL_NAME_num(gens); idx++) {
1152 GENERAL_NAME *gen;
1153 ASN1_STRING *cstr;
1154 gen = sk_GENERAL_NAME_value(gens, idx);
1155 if (gen->type != GEN_DNS)
1156 continue;
1157 cstr = gen->d.dNSName;
1158 if (ASN1_STRING_type(cstr) != V_ASN1_IA5STRING)
1159 continue;
1160 int san_fqdn_len = ASN1_STRING_length(cstr);
1161 if (san_fqdn_len > 255)
1162 continue;
1163 memcpy(san_fqdn, ASN1_STRING_get0_data(cstr), san_fqdn_len);
1164 san_fqdn[san_fqdn_len] = '\0';
1165 if (strlen(san_fqdn) != static_cast<size_t>(san_fqdn_len)) // Avoid embedded null's.
1166 continue;
1167 DEBUG("Comparing SAN " << san_fqdn << " with " << fqdn);
1168 if (MatchHostnames(san_fqdn, fqdn)) {
1169 DEBUG("SAN " << san_fqdn << " matches with " << fqdn);
1170 success = true;
1171 break;
1172 }
1173 }
1174 sk_GENERAL_NAME_pop_free(gens, GENERAL_NAME_free);
1175 return success;
1176}
long long kXR_int64
Definition XPtypes.hh:98
#define DEBUG(x)
#define EPNAME(x)
void * XrdCryptoX509data
time_t XrdCryptosslASN1toUTC(const ASN1_TIME *tsn1)
void XrdCryptosslNameOneLine(const X509_NAME *nm, XrdOucString &s)
int XrdCryptosslX509CheckProxy3(XrdCryptoX509 *, XrdOucString &)
#define PRINT(y)
#define BIO_PRINT(b, c)
int fclose(FILE *stream)
#define close(a)
Definition XrdPosix.hh:48
#define fstat(a, b)
Definition XrdPosix.hh:62
#define open
Definition XrdPosix.hh:78
#define stat(a, b)
Definition XrdPosix.hh:105
int emsg(int rc, char *msg)
@ kXRS_x509
Definition XrdSutAux.hh:79
#define TRACE(act, x)
Definition XrdTrace.hh:63
const char * SubjectHash()
virtual XrdCryptoX509data Opaque()
const char * IssuerHash()
static bool MatchHostnames(const char *match_pattern, const char *fqdn)
const char * Issuer()
XrdCryptoX509data GetExtension(const char *oid)
const char * Subject()
int DumpExtensions(bool dumpunknown=0)
XrdOucString SerialNumberString()
XrdCryptoX509data Opaque()
bool Verify(XrdCryptoX509 *ref)
XrdSutBucket * Export()
virtual bool MatchesSAN(const char *, bool &)
XrdCryptosslX509(const char *cf, const char *kf=0)
void SetPKI(XrdCryptoX509data pki)
kXR_int32 size