2 Common functions used by the NSS-aware code in systemtap.
4 Copyright (C) 2009-2018 Red Hat Inc.
6 This file is part of systemtap, and is free software. You can
7 redistribute it and/or modify it under the terms of the GNU General Public
8 License as published by the Free Software Foundation; either version 2 of the
9 License, or (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program. If not, see <http://www.gnu.org/licenses/>.
35 #include <sys/utsname.h>
46 #ifdef HAVE_HTTP_SUPPORT
47 #include <openssl/bio.h>
48 #include <openssl/x509.h>
49 #include <openssl/pem.h>
50 #include <openssl/x509v3.h>
54 #include "nsscommon.h"
59 // Common constants and settings.
61 server_cert_nickname ()
63 return (const char *)"stap-server";
67 add_cert_db_prefix (const string
&db_path
) {
68 #if 0 && ((NSS_VMAJOR > 3) || (NSS_VMAJOR == 3 && NSS_VMINOR >= 37))
69 // https://wiki.mozilla.org/NSS_Shared_DB
70 if (db_path
.find (':') == string::npos
)
71 return string("sql:") + db_path
;
72 #elif (NSS_VMAJOR > 3) || (NSS_VMAJOR == 3 && NSS_VMINOR >= 12)
73 // Use the dbm prefix, if a prefix is not already specified,
74 // since we're using the old database format.
75 if (db_path
.find (':') == string::npos
)
76 return string("dbm:") + db_path
;
82 server_cert_db_path ()
85 const char* s_d
= getenv ("SYSTEMTAP_DIR");
89 data_path
= get_home_directory() + string("/.systemtap");
90 return data_path
+ "/ssl/server";
94 local_client_cert_db_path ()
97 const char* s_d
= getenv ("SYSTEMTAP_DIR");
101 data_path
= get_home_directory() + string("/.systemtap");
102 return data_path
+ "/ssl/client";
105 // Common error handling for applications using this file.
107 nsscommon_error (const string
&msg
, int logit
)
109 // Call the extern "C" version supplied by each application.
110 nsscommon_error (msg
.c_str (), logit
);
113 // Logging. Enabled only by stap-serverd but called from some common methods.
114 static ofstream logfile
;
117 start_log (const char *arg
, bool redirect_clog
)
119 if (logfile
.is_open ())
122 logfile
.open (arg
, ios_base::app
);
123 if (! logfile
.good ())
124 nsscommon_error (_F("Could not open log file %s", arg
));
125 else if (redirect_clog
)
126 clog
.rdbuf(logfile
.rdbuf());
132 return logfile
.good ();
136 log (const string
&msg
)
141 string nowStr
= ctime (& now
);
142 // Remove the newline from the end of the time string.
143 nowStr
.erase (nowStr
.size () - 1, 1);
146 logfile
<< nowStr
<< ": " << msg
<< endl
<< flush
;
148 clog
<< nowStr
<< ": " << msg
<< endl
<< flush
;
154 if (logfile
.is_open ())
158 // NSS/NSPR error reporting and cleanup.
159 // These functions are called from C code as well as C++, so make them extern "C".
164 // See if PR_GetError can tell us what the error is.
165 PRErrorCode errorNumber
= PR_GetError ();
167 // Try PR_ErrorToName and PR_ErrorToString; they are wise.
168 const char* errorName
= PR_ErrorToName(errorNumber
);
169 const char* errorText
= PR_ErrorToString (errorNumber
, PR_LANGUAGE_EN
);
171 if (errorName
&& errorText
)
173 nsscommon_error (_F("(%d %s) %s", errorNumber
, errorName
, errorText
));
177 // Fall back to our own scraped ssl error text.
178 switch (errorNumber
) {
179 default: errorText
= "Unknown error"; break;
180 #define NSSYERROR(code,msg) case code: errorText = msg; break
181 #include "stapsslerr.h"
184 nsscommon_error (_F("(%d) %s", errorNumber
, errorText
));
189 nssInit (const char *db_path
, int readWrite
, int issueMessage
)
192 string full_db_path
= add_cert_db_prefix (db_path
);
193 db_path
= full_db_path
.c_str();
195 secStatus
= NSS_InitReadWrite (db_path
);
197 secStatus
= NSS_Init (db_path
);
198 if (secStatus
!= SECSuccess
&& issueMessage
)
200 nsscommon_error (_F("Error initializing NSS for %s", db_path
));
208 nssCleanup (const char *db_path
)
210 // Make sure that NSS has been initialized. Some early versions of NSS do not check this
211 // within NSS_Shutdown().
212 // When called with no certificate database path (db_path == 0), then the caller does
213 // not know whether NSS has actually been initialized. For example, the rpm finder,
214 // which calls here to shutdown NSS manually if rpmFreeCrypto() is not available
215 // (see rpm_finder.cxx:missing_rpm_enlist).
216 // However, if we're trying to close a certificate database which has not been initialized,
217 // then we have a (non fatal) internal error.
218 if (! NSS_IsInitialized ())
222 string full_db_path
= add_cert_db_prefix (db_path
);
223 db_path
= full_db_path
.c_str();
224 nsscommon_error (_F("WARNING: Attempt to shutdown NSS for database %s, which was never initialized", db_path
));
229 // Shutdown NSS and ensure that it went down successfully. This is because we can not
230 // initialize NSS again if it does not.
231 if (NSS_Shutdown () != SECSuccess
)
235 string full_db_path
= add_cert_db_prefix (db_path
);
236 db_path
= full_db_path
.c_str();
237 nsscommon_error (_F("Unable to shutdown NSS for database %s", db_path
));
240 nsscommon_error (_("Unable to shutdown NSS"));
245 // Certificate database password support functions.
247 // Disable character echoing, if the fd is a tty.
254 tio
.c_lflag
&= ~ECHO
;
255 tcsetattr(fd
, TCSAFLUSH
, &tio
);
259 /* Enable character echoing, if the fd is a tty. */
267 tcsetattr(fd
, TCSAFLUSH
, &tio
);
272 * This function is our custom password handler that is called by
273 * NSS when retrieving private certs and keys from the database. Returns a
274 * pointer to a string with a password for the database. Password pointer
275 * must be allocated by one of the NSPR memory allocation functions, or by PORT_Strdup,
276 * and will be freed by the caller.
280 nssPasswordCallback (PK11SlotInfo
*info
__attribute ((unused
)), PRBool retry
, void *arg
)
282 static int retries
= 0;
284 char* password
= NULL
;
285 char* password_ret
= NULL
;
297 /* Maximum of 2 retries for bad password. */
299 return NULL
; /* No more retries */
302 /* Can only prompt for a password if stdin is a tty. */
303 infd
= fileno (stdin
);
304 isTTY
= isatty (infd
);
307 nsscommon_error (_("Cannot prompt for certificate database password. stdin is not a tty"));
311 /* Prompt for password */
312 password
= (char *)PORT_Alloc (PW_MAX
);
319 dbname
= (const char *)arg
;
320 cerr
<< _F("Password for certificate database in %s: ", dbname
) << flush
;
322 password_ret
= fgets (password
, PW_MAX
, stdin
);
323 cerr
<< endl
<< flush
;
327 /* stomp on the newline */
328 *strchrnul (password
, '\n') = '\0';
330 PORT_Free (password
);
336 create_server_cert_db (const char *db_path
)
338 return create_dir (db_path
, 0755);
342 create_client_cert_db (const char *db_path
)
344 // Same properties as the server's database, at present.
345 return create_server_cert_db (db_path
);
349 clean_cert_db (const string
&db_path
)
351 // First remove all files from the directory
353 string filespec
= db_path
+ "/*";
354 int r
= glob (filespec
.c_str (), 0, NULL
, & globbuf
);
355 if (r
== GLOB_NOSPACE
|| r
== GLOB_ABORTED
)
356 nsscommon_error (_F("Could not search certificate database directory %s", db_path
.c_str ()));
357 else if (r
!= GLOB_NOMATCH
)
359 for (unsigned i
= 0; i
< globbuf
.gl_pathc
; ++i
)
361 if (remove_file_or_dir (globbuf
.gl_pathv
[i
]) != 0)
362 nsscommon_error (_F("Could not remove %s", globbuf
.gl_pathv
[i
]));
367 // Now remove the directory itself.
368 if (remove_file_or_dir (db_path
.c_str ()) != 0)
370 nsscommon_error (_F("Could not remove certificate database directory %s\n%s",
371 db_path
.c_str (), strerror (errno
)));
379 init_password (PK11SlotInfo
*slot
, const string
&db_path
, bool use_password
)
381 // Prompt for the database password, if we're using one. Keep the passwords in memory for as
382 // little time as possible.
388 const int max_attempts
= 3;
389 for (attempts
= 0; attempts
< max_attempts
; ++attempts
)
391 pw1
= nssPasswordCallback (slot
, false, (void*)db_path
.c_str ());
396 char *pw2
= nssPasswordCallback (slot
, false, (void*)db_path
.c_str ());
399 if (strcmp (pw1
, pw2
) == 0)
402 nsscommon_error (_("Passwords do not match"));
403 memset (pw2
, 0, strlen (pw2
));
408 memset (pw1
, 0, strlen (pw1
));
411 if (attempts
>= max_attempts
)
413 nsscommon_error (_("Too many password attempts"));
416 secStatus
= PK11_InitPin (slot
, 0, pw1
);
417 memset (pw1
, 0, strlen (pw1
));
421 secStatus
= PK11_InitPin (slot
, 0, 0);
423 if (secStatus
!= SECSuccess
)
425 nsscommon_error (_F("Could not initialize pin for certificate database %s", db_path
.c_str()));
433 static SECKEYPrivateKey
*
434 generate_private_key (const string
&db_path
, PK11SlotInfo
*slot
, SECKEYPublicKey
**pubkeyp
)
436 if (PK11_Authenticate (slot
, PR_TRUE
, 0) != SECSuccess
)
438 nsscommon_error (_F("Unable to authenticate the default slot for certificate database %s",
444 // Do some random-number initialization.
445 // TODO: We can do better.
448 for (unsigned i
= 0; i
< sizeof (randbuf
); ++i
)
449 randbuf
[i
] = rand ();
450 PK11_RandomUpdate (randbuf
, sizeof (randbuf
));
451 memset (randbuf
, 0, sizeof (randbuf
));
454 PK11RSAGenParams rsaparams
;
455 rsaparams
.keySizeInBits
= 4096; /* 1024 too small; SEC_ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED */
456 rsaparams
.pe
= 0x010001;
457 CK_MECHANISM_TYPE mechanism
= CKM_RSA_PKCS_KEY_PAIR_GEN
;
459 // Generate the key pair.
460 SECKEYPrivateKey
*privKey
= PK11_GenerateKeyPair (slot
, mechanism
, & rsaparams
, pubkeyp
,
461 PR_TRUE
/*isPerm*/, PR_TRUE
/*isSensitive*/,
465 nsscommon_error (_("Unable to generate public/private key pair"));
471 static CERTCertificateRequest
*
472 generate_cert_request (SECKEYPublicKey
*pubk
, CERTName
*subject
)
474 CERTSubjectPublicKeyInfo
*spki
= SECKEY_CreateSubjectPublicKeyInfo (pubk
);
477 nsscommon_error (_("Unable to create subject public key info for certificate request"));
482 /* Generate certificate request */
483 CERTCertificateRequest
*cr
= CERT_CreateCertificateRequest (subject
, spki
, 0);
484 SECKEY_DestroySubjectPublicKeyInfo (spki
);
487 nsscommon_error (_("Unable to create certificate request"));
493 static CERTCertificate
*
494 create_cert (CERTCertificateRequest
*certReq
, const string
&dnsNames
)
496 // What is the current date and time?
497 PRTime now
= PR_Now ();
499 // What is the date and time 1 year from now?
500 PRExplodedTime printableTime
;
501 PR_ExplodeTime (now
, PR_GMTParameters
, & printableTime
);
502 printableTime
.tm_month
+= 12;
503 PRTime after
= PR_ImplodeTime (& printableTime
);
505 // Note that the time is now in micro-second units.
506 CERTValidity
*validity
= CERT_CreateValidity (now
, after
);
509 nsscommon_error (_("Unable to create certificate validity dates"));
514 // Create a default serial number using the current time.
515 PRTime serialNumber
= now
>> 19; // copied from certutil.
517 // Create the certificate.
518 CERTCertificate
*cert
= CERT_CreateCertificate (serialNumber
, & certReq
->subject
, validity
,
520 CERT_DestroyValidity (validity
);
523 nsscommon_error (_("Unable to create certificate"));
528 // Predeclare these to keep C++ happy about jumps to the label 'error'.
529 SECStatus secStatus
= SECSuccess
;
530 unsigned char keyUsage
= 0x0;
531 PRArenaPool
*arena
= 0;
533 // Add the extensions that we need.
534 void *extHandle
= CERT_StartCertExtensions (cert
);
537 nsscommon_error (_("Unable to allocate certificate extensions"));
542 // Cert type extension.
543 keyUsage
|= (0x80 >> 1); // SSL Server
544 keyUsage
|= (0x80 >> 3); // Object signer
545 keyUsage
|= (0x80 >> 7); // Object signing CA
547 SECItem bitStringValue
;
548 bitStringValue
.data
= & keyUsage
;
549 bitStringValue
.len
= 1;
551 secStatus
= CERT_EncodeAndAddBitStrExtension (extHandle
,
552 SEC_OID_NS_CERT_EXT_CERT_TYPE
,
553 & bitStringValue
, PR_TRUE
);
554 if (secStatus
!= SECSuccess
)
556 nsscommon_error (_("Unable to encode certificate type extensions"));
561 // Alternate dns name extension.
562 if (! dnsNames
.empty ())
564 arena
= PORT_NewArena (DER_DEFAULT_CHUNKSIZE
);
567 nsscommon_error (_("Unable to allocate alternate DNS name extension for certificate"));
571 // Walk down the comma separated list of names.
572 CERTGeneralName
*nameList
= 0;
573 CERTGeneralName
*current
= 0;
575 vector
<string
>components
;
576 tokenize (dnsNames
, components
, ",");
577 for (unsigned i
= 0; i
< components
.size (); ++i
)
579 char *tbuf
= (char *)PORT_ArenaAlloc (arena
, components
[i
].size () + 1);
580 strcpy (tbuf
, components
[i
].c_str ());
582 current
= (CERTGeneralName
*)PORT_ZAlloc (sizeof (CERTGeneralName
));
585 nsscommon_error (_("Unable to allocate alternate DNS name extension for certificate"));
590 current
->l
.prev
= prev
;
591 prev
->next
= & current
->l
;
596 current
->type
= certDNSName
;
597 current
->name
.other
.data
= (unsigned char *)tbuf
;
598 current
->name
.other
.len
= strlen (tbuf
);
602 // At this point nameList points to the head of a doubly linked,
603 // but not yet circular, list and current points to its tail.
606 // Make nameList circular.
607 nameList
->l
.prev
= prev
;
608 current
->l
.next
= & nameList
->l
;
610 // Encode and add the extension.
612 secStatus
= CERT_EncodeAltNameExtension (arena
, nameList
, & item
);
613 if (secStatus
!= SECSuccess
)
615 nsscommon_error (_("Unable to encode alternate DNS name extension for certificate"));
619 secStatus
= CERT_AddExtension(extHandle
,
620 SEC_OID_X509_SUBJECT_ALT_NAME
,
621 & item
, PR_FALSE
, PR_TRUE
);
622 if (secStatus
!= SECSuccess
)
624 nsscommon_error (_("Unable to add alternate DNS name extension for certificate"));
629 } // extra dns names specified.
631 // We did not create any extensions on the cert request.
632 assert (certReq
->attributes
!= NULL
);
633 assert (certReq
->attributes
[0] == NULL
);
635 // Finished with cert extensions.
636 secStatus
= CERT_FinishExtensions (extHandle
);
637 if (secStatus
!= SECSuccess
)
639 nsscommon_error (_("Unable to complete alternate DNS name extension for certificate"));
648 PORT_FreeArena (arena
, PR_FALSE
);
649 CERT_DestroyCertificate (cert
);
654 sign_cert (CERTCertificate
*cert
, SECKEYPrivateKey
*privKey
)
656 SECOidTag algID
= SEC_GetSignatureAlgorithmOidTag (privKey
->keyType
,
658 if (algID
== SEC_OID_UNKNOWN
)
660 nsscommon_error (_("Unable to determine the signature algorithm for the signing the certificate"));
665 PRArenaPool
*arena
= cert
->arena
;
666 SECStatus rv
= SECOID_SetAlgorithmID (arena
, & cert
->signature
, algID
, 0);
667 if (rv
!= SECSuccess
)
669 nsscommon_error (_("Unable to set the signature algorithm for signing the certificate"));
674 /* we only deal with cert v3 here */
675 *(cert
->version
.data
) = 2;
676 cert
->version
.len
= 1;
681 void *dummy
= SEC_ASN1EncodeItem (arena
, & der
, cert
,
682 SEC_ASN1_GET (CERT_CertificateTemplate
));
685 nsscommon_error (_("Unable to encode the certificate for signing"));
690 SECItem
*result
= (SECItem
*)PORT_ArenaZAlloc (arena
, sizeof (SECItem
));
693 nsscommon_error (_("Unable to allocate memory for signing the certificate"));
697 rv
= SEC_DerSignData (arena
, result
, der
.data
, der
.len
, privKey
, algID
);
698 if (rv
!= SECSuccess
)
700 nsscommon_error (_("Unable to sign the certificate"));
705 cert
->derCert
= *result
;
710 add_server_cert (const string
&db_path
, SECItem
*certDER
, PK11SlotInfo
*slot
)
713 CERTCertificate
*cert
= CERT_DecodeCertFromPackage((char *)certDER
->data
, certDER
->len
);
716 nsscommon_error (_("Unable to decode certificate"));
721 // Import it into the database.
722 CERTCertDBHandle
*handle
= 0;
723 CERTCertTrust
*trust
= NULL
;
724 SECStatus secStatus
= PK11_ImportCert (slot
, cert
, CK_INVALID_HANDLE
,
725 server_cert_nickname (), PR_FALSE
);
726 if (secStatus
!= SECSuccess
)
728 nsscommon_error (_F("Unable to import certificate into the database at %s", db_path
.c_str ()));
733 // Make it a trusted server and signer.
734 trust
= (CERTCertTrust
*)PORT_ZAlloc (sizeof (CERTCertTrust
));
737 nsscommon_error (_("Unable to allocate certificate trust"));
738 secStatus
= SECFailure
;
742 secStatus
= CERT_DecodeTrustString (trust
, "PCu,,PCu");
743 if (secStatus
!= SECSuccess
)
745 nsscommon_error (_("Unable decode trust string 'PCu,,PCu'"));
750 handle
= CERT_GetDefaultCertDB ();
752 secStatus
= CERT_ChangeCertTrust (handle
, cert
, trust
);
753 if (secStatus
!= SECSuccess
)
755 nsscommon_error (_("Unable to change certificate trust"));
760 CERT_DestroyCertificate (cert
);
767 add_client_cert (const string
&inFileName
, const string
&db_path
, bool init_db
)
769 FILE *inFile
= fopen (inFileName
.c_str (), "rb");
772 nsscommon_error (_F("Could not open certificate file %s for reading\n%s",
773 inFileName
.c_str (), strerror (errno
)));
777 int fd
= fileno (inFile
);
779 int rc
= fstat (fd
, &info
);
782 nsscommon_error (_F("Could not obtain information about certificate file %s\n%s",
783 inFileName
.c_str (), strerror (errno
)));
789 certDER
.len
= info
.st_size
;
790 certDER
.data
= (unsigned char *)PORT_Alloc (certDER
.len
);
791 if (certDER
.data
== NULL
)
793 nsscommon_error (_F("Could not allocate certDER\n%s",
798 size_t read
= fread (certDER
.data
, 1, certDER
.len
, inFile
);
800 if (read
!= certDER
.len
)
802 nsscommon_error (_F("Error reading from certificate file %s\n%s",
803 inFileName
.c_str (), strerror (errno
)));
810 // The http client adds a cert by calling us via add_server_trust which
811 // first has already called nssInit; we don't want to call nssInit twice
812 // See if the database already exists and can be initialized.
813 secStatus
= nssInit (db_path
.c_str (), 1/*readwrite*/, 0/*issueMessage*/);
814 if (secStatus
!= SECSuccess
)
816 // Try again with a fresh database.
817 if (clean_cert_db (db_path
.c_str ()) != 0)
819 // Message already issued.
823 // Make sure the given path exists.
824 if (create_client_cert_db (db_path
.c_str ()) != 0)
826 nsscommon_error (_F("Could not create certificate database directory %s",
831 // Initialize the new database.
832 secStatus
= nssInit (db_path
.c_str (), 1/*readwrite*/);
833 if (secStatus
!= SECSuccess
)
835 // Message already issued.
841 // Predeclare these to keep C++ happy about jumps to the label 'done'.
842 CERTCertificate
*cert
= 0;
843 CERTCertDBHandle
*handle
= 0;
844 CERTCertTrust
*trust
= 0;
845 PK11SlotInfo
*slot
= 0;
847 // Add the cert to the database
849 secStatus
= SECFailure
;
850 cert
= CERT_DecodeCertFromPackage ((char *)certDER
.data
, certDER
.len
);
853 nsscommon_error (_("Unable to decode certificate"));
858 // We need the internal slot for this database.
859 slot
= PK11_GetInternalKeySlot ();
862 nsscommon_error (_F("Could not obtain internal key slot for certificate database %s", db_path
.c_str()));
867 // Import it into the database.
868 secStatus
= PK11_ImportCert (slot
, cert
, CK_INVALID_HANDLE
,
869 server_cert_nickname (), PR_FALSE
);
870 if (secStatus
!= SECSuccess
)
872 nsscommon_error (_F("Could not import certificate into the database at %s", db_path
.c_str()));
877 // Make it a trusted SSL peer.
878 trust
= (CERTCertTrust
*)PORT_ZAlloc (sizeof (CERTCertTrust
));
881 nsscommon_error (_("Could not allocate certificate trust"));
885 secStatus
= CERT_DecodeTrustString (trust
, "P,P,P");
886 if (secStatus
!= SECSuccess
)
888 nsscommon_error (_("Unable decode trust string 'P,P,P'"));
893 handle
= CERT_GetDefaultCertDB ();
895 secStatus
= CERT_ChangeCertTrust (handle
, cert
, trust
);
896 if (secStatus
!= SECSuccess
)
898 nsscommon_error (_("Unable to change certificate trust"));
903 // Free NSS/NSPR objects and shutdown NSS.
905 PK11_FreeSlot (slot
);
909 CERT_DestroyCertificate (cert
);
911 PORT_Free (certDER
.data
);
913 nssCleanup (db_path
.c_str ());
915 // Make sure that the cert database files are read/write by the owner and
918 string filespec
= db_path
+ "/*";
919 int r
= glob (filespec
.c_str (), 0, NULL
, & globbuf
);
920 if (r
== GLOB_NOSPACE
|| r
== GLOB_ABORTED
) {
921 // Not fatal, just a warning
922 nsscommon_error (_F("Could not search certificate database directory %s", db_path
.c_str ()));
924 else if (r
!= GLOB_NOMATCH
)
926 mode_t mode
= S_IRUSR
| S_IWUSR
| S_IRGRP
| S_IROTH
;
927 for (unsigned i
= 0; i
< globbuf
.gl_pathc
; ++i
)
929 // Not fatal, just a warning
930 if (chmod (globbuf
.gl_pathv
[i
], mode
) != 0)
931 nsscommon_error (_F("Could set file permissions for %s", globbuf
.gl_pathv
[i
]));
940 gen_cert_db (const string
&db_path
, const string
&extraDnsNames
, bool use_password
)
942 // Log the generation of a new database.
943 log (_F("Generating a new certificate database directory in %s",
946 // Start with a clean cert database.
947 if (clean_cert_db (db_path
.c_str ()) != 0)
949 // Message already issued.
953 // Make sure the given path exists.
954 if (create_server_cert_db (db_path
.c_str ()) != 0)
956 nsscommon_error (_F("Could not create certificate database directory %s",
961 // Initialize the new database.
962 SECStatus secStatus
= nssInit (db_path
.c_str (), 1/*readwrite*/);
963 if (secStatus
!= SECSuccess
)
965 // Message already issued.
969 // Pre declare these to keep g++ happy about jumps to the label 'error'.
970 CERTName
*subject
= 0;
971 SECKEYPublicKey
*pubkey
= 0;
972 SECKEYPrivateKey
*privkey
= 0;
973 CERTCertificateRequest
*cr
= 0;
974 CERTCertificate
*cert
= 0;
975 SECItem
*certDER
= 0;
982 // We need the internal slot for this database.
983 PK11SlotInfo
*slot
= PK11_GetInternalKeySlot ();
986 nsscommon_error (_F("Could not obtain internal key slot for certificate database %s", db_path
.c_str()));
991 // Establish the password (if any) for the new database.
992 rc
= init_password (slot
, db_path
, use_password
);
995 // Messages already issued.
999 // Format the cert subject.
1000 subject
= CERT_AsciiToName ((char *)"CN=Systemtap Compile Server, OU=Systemtap");
1003 nsscommon_error (_("Unable to encode certificate common header"));
1008 // Next, generate the private key.
1009 privkey
= generate_private_key (db_path
, slot
, & pubkey
);
1012 // Message already issued.
1016 // Next, generate a cert request.
1017 cr
= generate_cert_request (pubkey
, subject
);
1020 // Message already issued.
1024 // For the cert, we need our host name.
1025 struct utsname utsname
;
1027 dnsNames
= utsname
.nodename
;
1029 // Because avahi identifies hosts using a ".local" domain, add one to the list of names.
1030 hostname
= dnsNames
.substr (0, dnsNames
.find ('.'));
1031 dnsNames
+= string(",") + hostname
+ ".local";
1033 // Add any extra names that were supplied.
1034 if (! extraDnsNames
.empty ())
1035 dnsNames
+= "," + extraDnsNames
;
1037 // Now, generate the cert.
1038 cert
= create_cert (cr
, dnsNames
);
1039 CERT_DestroyCertificateRequest (cr
);
1042 // NSS error already issued.
1043 nsscommon_error (_("Unable to create certificate"));
1048 certDER
= sign_cert (cert
, privkey
);
1051 // Message already issued.
1055 // Now output it to a file.
1056 outFileName
= db_path
+ "/stap.cert";
1057 outFile
= fopen (outFileName
.c_str (), "wb");
1060 size_t written
= fwrite (certDER
->data
, 1, certDER
->len
, outFile
);
1061 if (written
!= certDER
->len
)
1063 nsscommon_error (_F("Error writing to certificate file %s\n%s",
1064 outFileName
.c_str (), strerror (errno
)));
1070 nsscommon_error (_F("Could not open certificate file %s for writing\n%s",
1071 outFileName
.c_str (), strerror (errno
)));
1074 // Add the cert to the database
1075 secStatus
= add_server_cert (db_path
, certDER
, slot
);
1076 CERT_DestroyCertificate (cert
);
1077 if (secStatus
!= SECSuccess
)
1079 // NSS error already issued.
1080 nsscommon_error (_F("Unable to add certificate to %s", db_path
.c_str ()));
1084 // Done with the certificate database
1085 PK11_FreeSlot (slot
);
1086 CERT_DestroyName (subject
);
1087 SECKEY_DestroyPublicKey (pubkey
);
1088 SECKEY_DestroyPrivateKey (privkey
);
1093 PK11_FreeSlot (slot
);
1095 CERT_DestroyName (subject
);
1097 SECKEY_DestroyPublicKey (pubkey
);
1099 SECKEY_DestroyPrivateKey (privkey
);
1101 CERT_DestroyCertificate (cert
); // Also destroys certDER.
1104 nssCleanup (db_path
.c_str ());
1105 return secStatus
!= SECSuccess
;
1108 CERTCertList
*get_cert_list_from_db (const string
&cert_nickname
)
1110 // Search the client-side database of trusted servers.
1111 CERTCertDBHandle
*handle
= CERT_GetDefaultCertDB ();
1113 CERTCertificate
*db_cert
= PK11_FindCertFromNickname (cert_nickname
.c_str (), 0);
1116 // No trusted servers. Not an error. Just an empty list returned.
1120 // Here, we have one cert with the desired nickname.
1121 // Now, we will attempt to get a list of ALL certs
1122 // with the same subject name as the cert we have. That list
1123 // should contain, at a minimum, the one cert we have already found.
1124 // If the list of certs is empty (0), the libraries have failed.
1125 CERTCertList
*certs
= CERT_CreateSubjectCertList (0, handle
, & db_cert
->derSubject
,
1126 PR_Now (), PR_FALSE
);
1127 CERT_DestroyCertificate (db_cert
);
1130 nsscommon_error (_("NSS library failure in CERT_CreateSubjectCertList"));
1138 format_cert_validity_time (SECItem
&vTime
, char *timeString
, size_t ts_size
)
1141 SECStatus secStatus
;
1143 switch (vTime
.type
) {
1145 secStatus
= DER_UTCTimeToTime (& time
, & vTime
);
1147 case siGeneralizedTime
:
1148 secStatus
= DER_GeneralizedTimeToTime (& time
, & vTime
);
1151 nsscommon_error (_("Could not decode certificate validity"));
1154 if (secStatus
!= SECSuccess
)
1156 nsscommon_error (_("Could not decode certificate validity time"));
1160 // Convert to local time.
1161 PRExplodedTime printableTime
;
1162 PR_ExplodeTime (time
, PR_GMTParameters
, & printableTime
);
1163 if (! PR_FormatTime (timeString
, ts_size
, "%a %b %d %H:%M:%S %Y", & printableTime
))
1165 nsscommon_error (_("Could not format certificate validity time"));
1173 cert_is_valid (CERTCertificate
*cert
)
1175 // Verify the the certificate is valid as an SSL server and as an object signer and that
1177 CERTCertDBHandle
*handle
= CERT_GetDefaultCertDB ();
1179 SECCertificateUsage usage
= certificateUsageSSLServer
| certificateUsageObjectSigner
;
1180 SECStatus secStatus
= CERT_VerifyCertificate (handle
, cert
, PR_TRUE
/*checkSig*/, usage
,
1181 PR_Now (), NULL
, NULL
/*log*/, & usage
);
1182 return secStatus
== SECSuccess
;
1187 get_host_name (CERTCertificate
*c
, string
&host_name
)
1189 // Get the host name. It is in the alt-name extension of the
1192 SECStatus secStatus
;
1193 PRArenaPool
*tmpArena
= NULL
;
1194 // A memory pool to work in
1195 tmpArena
= PORT_NewArena(DER_DEFAULT_CHUNKSIZE
);
1198 clog
<< _("Out of memory:");
1203 subAltName
.data
= NULL
;
1204 secStatus
= CERT_FindCertExtension (c
,
1205 SEC_OID_X509_SUBJECT_ALT_NAME
,
1207 if (secStatus
!= SECSuccess
|| ! subAltName
.data
)
1209 clog
<< _("Unable to find alt name extension on server certificate: ") << endl
;
1210 PORT_FreeArena (tmpArena
, PR_FALSE
);
1214 // Decode the extension.
1215 CERTGeneralName
*nameList
= CERT_DecodeAltNameExtension (tmpArena
, & subAltName
);
1216 SECITEM_FreeItem(& subAltName
, PR_FALSE
);
1219 clog
<< _("Unable to decode alt name extension on server certificate: ") << endl
;
1223 // We're interested in the first alternate name.
1224 assert (nameList
->type
== certDNSName
);
1225 host_name
= string ((const char *)nameList
->name
.other
.data
,
1226 nameList
->name
.other
.len
);
1227 PORT_FreeArena (tmpArena
, PR_FALSE
);
1232 cert_db_is_valid (const string
&db_path
, const string
&nss_cert_name
,
1233 CERTCertificate
*this_cert
)
1235 // Make sure the given path exists.
1236 if (! file_exists (db_path
))
1238 log (_F("Certificate database %s does not exist", db_path
.c_str ()));
1242 // If a 'pw' file exists, then this is an old database. Treat any certs as invalid.
1243 if (file_exists (db_path
+ "/pw"))
1245 log (_F("Certificate database %s is obsolete", db_path
.c_str ()));
1249 // Initialize the NSS libraries -- readonly
1250 SECStatus secStatus
= nssInit (db_path
.c_str ());
1251 if (secStatus
!= SECSuccess
)
1253 // Message already issued.
1257 // Obtain a list of our certs from the database.
1258 bool valid_p
= false;
1259 CERTCertList
*certs
= get_cert_list_from_db (nss_cert_name
);
1262 log (_F("No certificate found in database %s", db_path
.c_str ()));
1266 log (_F("Certificate found in database %s", db_path
.c_str ()));
1267 for (CERTCertListNode
*node
= CERT_LIST_HEAD (certs
);
1268 ! CERT_LIST_END (node
, certs
);
1269 node
= CERT_LIST_NEXT (node
))
1271 // The certificate we're working with.
1272 CERTCertificate
*c
= node
->cert
;
1274 // Print the validity dates of the certificate.
1275 CERTValidity
&v
= c
->validity
;
1276 char timeString
[256];
1277 if (format_cert_validity_time (v
.notBefore
, timeString
, sizeof (timeString
)) == 0)
1278 log (_F(" Not Valid Before: %s UTC", timeString
));
1279 if (format_cert_validity_time (v
.notAfter
, timeString
, sizeof (timeString
)) == 0)
1280 log (_F(" Not Valid After: %s UTC", timeString
));
1282 // Now ask NSS to check the validity.
1283 if (cert_is_valid (c
))
1285 // The cert is valid. One valid cert is enough.
1286 log (_("Certificate is valid"));
1293 // The cert is not valid. Look for another one.
1294 log (_("Certificate is not valid"));
1296 CERT_DestroyCertList (certs
);
1299 nssCleanup (db_path
.c_str ());
1304 #ifdef HAVE_HTTP_SUPPORT
1306 * Similar to cert_db_is_valid; additionally it checks host_name and does no logging
1309 get_pem_cert_is_valid (const string
&db_path
, const string
&nss_cert_name
,
1310 const string
&host_name
, CERTCertificate
*this_cert
)
1312 bool nss_already_init_p
= false;
1313 bool found_match
= false;
1315 if (! file_exists (db_path
))
1318 if (file_exists (db_path
+ "/pw"))
1321 if (NSS_IsInitialized ())
1322 nss_already_init_p
= true;
1324 if (nssInit (db_path
.c_str ()) != SECSuccess
)
1327 CERTCertList
*certs
= get_cert_list_from_db (nss_cert_name
);
1330 nssCleanup (db_path
.c_str ());
1334 for (CERTCertListNode
*node
= CERT_LIST_HEAD (certs
);
1335 ! CERT_LIST_END (node
, certs
);
1336 node
= CERT_LIST_NEXT (node
))
1338 CERTCertificate
*c
= node
->cert
;
1339 // An http client searches for the corresponding server's certificate
1340 if (host_name
.length() > 0)
1342 string cert_host_name
;
1343 if (get_host_name (c
, cert_host_name
) == false)
1346 if (cert_host_name
!= host_name
)
1349 if ((dot
= host_name
.find ('.')) == string::npos
1350 || cert_host_name
!= host_name
.substr(0,dot
))
1355 // Now ask NSS to check the validity.
1356 if (cert_is_valid (c
))
1364 CERT_DestroyCertList (certs
);
1366 // NSS shutdown is global and is forceful
1367 if (!nss_already_init_p
)
1368 nssCleanup (db_path
.c_str ());
1374 cvt_nss_to_pem (CERTCertificate
*c
, string
&cert_pem
)
1377 X509
*certificate_509
;
1379 bio
= BIO_new(BIO_s_mem());
1380 certificate_509
= X509_new();
1381 // Load the nss certificate into the openssl BIO
1382 int count
= BIO_write (bio
, (const void*)c
->derCert
.data
, c
->derCert
.len
);
1385 // Parse the BIO into an X509
1386 certificate_509
= d2i_X509_bio(bio
, &certificate_509
);
1387 // Convert the X509 to PEM form
1388 int rc
= PEM_write_bio_X509(bio
, certificate_509
);
1391 BUF_MEM
*mem
= NULL
;
1392 // Load the buffer from the PEM form
1393 BIO_get_mem_ptr(bio
, &mem
);
1394 cert_pem
= string(mem
->data
, mem
->length
);
1396 X509_free(certificate_509
);
1402 get_pem_cert (const string
&db_path
, const string
&nss_cert_name
, const string
&host
,
1406 CERTCertificate
*c
= &cc
;
1407 // Do we have an nss certificate in the nss cert db for server host?
1408 if (get_pem_cert_is_valid (db_path
, nss_cert_name
, host
, c
))
1410 // If we do, then convert to PEM form
1411 cvt_nss_to_pem (c
, cert
);
1418 have_san_match (string
& hostname
, string
& pem_cert
)
1420 bool have_match
= false;
1421 STACK_OF (GENERAL_NAME
) * san_names
= NULL
;
1423 BIO
*bio
= BIO_new(BIO_s_mem());
1424 BIO_puts(bio
, pem_cert
.c_str());
1425 X509
*server_cert
= PEM_read_bio_X509(bio
, NULL
, NULL
, NULL
);
1427 // Extract the source alternate names from the certificate
1429 (stack_st_GENERAL_NAME
*) X509_get_ext_d2i ((X509
*) server_cert
,
1430 NID_subject_alt_name
, NULL
,
1432 if (san_names
== NULL
)
1437 for (int i
= 0; i
< sk_GENERAL_NAME_num (san_names
); i
++)
1439 const GENERAL_NAME
*current_name
= sk_GENERAL_NAME_value (san_names
, i
);
1441 if (current_name
->type
== GEN_DNS
)
1443 const int scheme_len
= 8; // https://
1445 #if OPENSSL_VERSION_NUMBER<0x10100000L
1446 string ((char *) ASN1_STRING_data (current_name
->d
.dNSName
));
1448 string ((char *) ASN1_STRING_get0_data (current_name
->d
.dNSName
));
1451 if ((size_t) ASN1_STRING_length (current_name
->d
.dNSName
) ==
1454 if (hostname
.compare(scheme_len
,dns_name
.length(), dns_name
))
1462 sk_GENERAL_NAME_pop_free (san_names
, GENERAL_NAME_free
);
1464 X509_free(server_cert
);
1471 // Ensure that our certificate exists and is valid. Generate a new one if not.
1473 check_cert (const string
&db_path
, const string
&nss_cert_name
, bool use_db_password
)
1475 // Generate a new cert database if the current one does not exist or is not valid.
1476 if (! cert_db_is_valid (db_path
, nss_cert_name
, NULL
))
1478 if (gen_cert_db (db_path
, "", use_db_password
) != 0)
1480 // NSS message already issued.
1481 nsscommon_error (_("Unable to generate new certificate"));
1489 const string
&db_path
,
1490 const string
&nss_cert_name
,
1491 const string
&inputName
,
1492 const string
&outputName
1494 /* Get own certificate and private key. */
1495 CERTCertificate
*cert
= PK11_FindCertFromNickname (nss_cert_name
.c_str (), NULL
);
1498 nsscommon_error (_F("Unable to find certificate with nickname %s in %s.",
1499 nss_cert_name
.c_str (), db_path
.c_str()));
1504 // Predeclare these to keep C++ happy abount branches to 'done'.
1505 unsigned char buffer
[4096];
1506 PRFileDesc
*local_file_fd
= NULL
;
1508 SECStatus secStatus
;
1512 /* db_path.c_str () gets passed to nssPasswordCallback */
1513 SECKEYPrivateKey
*privKey
= PK11_FindKeyByAnyCert (cert
, (void *)db_path
.c_str ());
1514 if (privKey
== NULL
)
1516 nsscommon_error (_F("Unable to obtain private key from the certificate with nickname %s in %s.",
1517 nss_cert_name
.c_str (), db_path
.c_str()));
1522 /* Sign the file. */
1523 /* Set up the signing context. */
1524 sgn
= SGN_NewContext (SEC_OID_PKCS1_SHA1_WITH_RSA_ENCRYPTION
, privKey
);
1527 nsscommon_error (_("Could not create signing context"));
1531 secStatus
= SGN_Begin (sgn
);
1532 if (secStatus
!= SECSuccess
)
1534 nsscommon_error (_("Could not initialize signing context."));
1539 /* Now read the data and add it to the signature. */
1540 local_file_fd
= PR_Open (inputName
.c_str(), PR_RDONLY
, 0);
1541 if (local_file_fd
== NULL
)
1543 nsscommon_error (_F("Could not open module file %s", inputName
.c_str ()));
1550 // No need for PR_Read_Complete here, since we're already managing multiple
1551 // reads to a fixed size buffer.
1552 numBytes
= PR_Read (local_file_fd
, buffer
, sizeof (buffer
));
1558 nsscommon_error (_F("Error reading module file %s", inputName
.c_str ()));
1563 /* Add the data to the signature. */
1564 secStatus
= SGN_Update (sgn
, buffer
, numBytes
);
1565 if (secStatus
!= SECSuccess
)
1567 nsscommon_error (_F("Error while signing module file %s", inputName
.c_str ()));
1573 /* Complete the signature. */
1574 secStatus
= SGN_End (sgn
, & signedData
);
1575 if (secStatus
!= SECSuccess
)
1577 nsscommon_error (_F("Could not complete signature of module file %s", inputName
.c_str ()));
1582 SGN_DestroyContext (sgn
, PR_TRUE
);
1584 /* Now write the signed data to the output file. */
1585 if(local_file_fd
!= NULL
)
1586 PR_Close (local_file_fd
);
1587 local_file_fd
= PR_Open (outputName
.c_str(), PR_WRONLY
| PR_CREATE_FILE
| PR_TRUNCATE
,
1588 PR_IRUSR
| PR_IWUSR
| PR_IRGRP
| PR_IWGRP
| PR_IROTH
);
1589 if (local_file_fd
== NULL
)
1591 nsscommon_error (_F("Could not open signature file %s", outputName
.c_str ()));
1596 numBytes
= PR_Write (local_file_fd
, signedData
.data
, signedData
.len
);
1597 if (numBytes
< 0 || numBytes
!= (PRInt32
)signedData
.len
)
1599 nsscommon_error (_F("Error writing to signature file %s", outputName
.c_str ()));
1605 SECKEY_DestroyPrivateKey (privKey
);
1606 CERT_DestroyCertificate (cert
);
1607 if(local_file_fd
!= NULL
)
1608 PR_Close (local_file_fd
);
1611 // PR_Read() is not guaranteed to read all of the requested data in one call.
1612 // Iterate until all of the requested data has been read.
1613 // Return the same values as PR_Read() would.
1614 PRInt32
PR_Read_Complete (PRFileDesc
*fd
, void *buf
, PRInt32 requestedBytes
)
1616 // Read until EOF or until the expected number of bytes has been read.
1617 // PR_Read wants (void*), but we need (char *) to do address arithmetic.
1618 char *buffer
= (char *)buf
;
1621 for (totalBytes
= 0; totalBytes
< requestedBytes
; totalBytes
+= bytesRead
)
1623 // Now read the data.
1624 bytesRead
= PR_Read (fd
, (void *)(buffer
+ totalBytes
), requestedBytes
- totalBytes
);
1628 return bytesRead
; // Error
1631 // Return the number of bytes we managed to read.
1636 read_cert_info_from_file (const string
&certPath
, string
&fingerprint
)
1638 FILE *certFile
= fopen (certPath
.c_str (), "rb");
1639 SECStatus secStatus
= SECFailure
;
1643 nsscommon_error (_F("Could not open certificate file %s for reading\n%s",
1644 certPath
.c_str (), strerror (errno
)));
1648 int fd
= fileno (certFile
);
1650 int rc
= fstat (fd
, &info
);
1653 nsscommon_error (_F("Could not obtain information about certificate file %s\n%s",
1654 certPath
.c_str (), strerror (errno
)));
1659 PLArenaPool
*arena
= PORT_NewArena(DER_DEFAULT_CHUNKSIZE
);
1662 nsscommon_error (_F("Could not create arena while decoding certificate from file %s",
1663 certPath
.c_str ()));
1669 if (!SECITEM_AllocItem(arena
, &derCert
, info
.st_size
))
1671 nsscommon_error (_F("Could not allocate DER cert\n%s",
1678 read
= fread (derCert
.data
, 1, derCert
.len
, certFile
);
1680 if (read
!= derCert
.len
)
1682 nsscommon_error (_F("Error reading from certificate file %s\n%s",
1683 certPath
.c_str (), strerror (errno
)));
1686 derCert
.type
= siDERCertBuffer
;
1688 // Sigh. We'd like to use CERT_DecodeDERCertificate() here, but
1689 // although /usr/include/nss3/cert.h declares them, the shared
1690 // library doesn't export them.
1692 CERTCertificate
*cert
;
1696 // Strip off the signature.
1698 sd
= PORT_ArenaZNew(arena
, CERTSignedData
);
1701 nsscommon_error (_F("Could not allocate signed data while decoding certificate from file %s",
1702 certPath
.c_str ()));
1705 rv
= SEC_ASN1DecodeItem(arena
, sd
, SEC_ASN1_GET(CERT_SignedDataTemplate
),
1709 nsscommon_error (_F("Could not decode signature while decoding certificate from file %s",
1710 certPath
.c_str ()));
1714 // Decode the certificate.
1715 cert
= PORT_ArenaZNew(arena
, CERTCertificate
);
1718 nsscommon_error (_F("Could not allocate cert while decoding certificate from file %s",
1719 certPath
.c_str ()));
1722 cert
->arena
= arena
;
1723 rv
= SEC_ASN1DecodeItem(arena
, cert
,
1724 SEC_ASN1_GET(CERT_CertificateTemplate
), &sd
->data
);
1727 nsscommon_error (_F("Could not decode certificate from file %s",
1728 certPath
.c_str ()));
1732 // Get the fingerprint from the signature.
1733 unsigned char fingerprint_buf
[SHA1_LENGTH
];
1735 rv
= PK11_HashBuf(SEC_OID_SHA1
, fingerprint_buf
, derCert
.data
, derCert
.len
);
1738 nsscommon_error (_F("Could not decode SHA1 fingerprint from file %s",
1739 certPath
.c_str ()));
1742 fpItem
.data
= fingerprint_buf
;
1743 fpItem
.len
= sizeof(fingerprint_buf
);
1744 str
= CERT_Hexify(&fpItem
, 1);
1747 nsscommon_error (_F("Could not hexify SHA1 fingerprint from file %s",
1748 certPath
.c_str ()));
1752 transform(fingerprint
.begin(), fingerprint
.end(), fingerprint
.begin(),
1755 secStatus
= SECSuccess
;
1759 PORT_FreeArena(arena
, PR_FALSE
);
1763 /* vim: set sw=2 ts=8 cino=>4,n-2,{2,^-2,t0,(0,u0,w1,M1 : */