1515// cert COMMON-NAME Create a certificate.
1616// client URI Connect to URI.
1717// csr COMMON-NAME Create a certificate signing request.
18+ // install COMMON-NAME FILENAME.crt [FILENAME.key]
19+ // Install a certificate and (optional) private key.
1820// server COMMON-NAME[:PORT] Run a HTTPS server (default port 8NNN.)
1921// show COMMON-NAME Show stored credentials for COMMON-NAME.
2022//
@@ -69,8 +71,10 @@ static int do_ca(const char *common_name, const char *csrfile, const char *root_
6971static int do_cert (bool ca_cert , cups_credpurpose_t purpose , cups_credtype_t type , cups_credusage_t keyusage , const char * organization , const char * org_unit , const char * locality , const char * state , const char * country , const char * root_name , const char * common_name , size_t num_alt_names , const char * * alt_names , int days );
7072static int do_client (const char * uri , bool pin , bool require_ca );
7173static int do_csr (cups_credpurpose_t purpose , cups_credtype_t type , cups_credusage_t keyusage , const char * organization , const char * org_unit , const char * locality , const char * state , const char * country , const char * common_name , size_t num_alt_names , const char * * alt_names );
74+ static int do_install (const char * common_name , const char * crtfile , const char * keyfile );
7275static int do_server (const char * host_port );
7376static int do_show (const char * common_name );
77+ static char * get_file (const char * filename );
7478static int usage (FILE * fp );
7579
7680
@@ -85,6 +89,8 @@ main(int argc, // I - Number of command-line arguments
8589 int i ; // Looping var
8690 const char * command = NULL , // Command
8791 * arg = NULL , // Argument for command
92+ * crtfile = NULL , // Certificate file for install command
93+ * keyfile = NULL , // Private key file for install command
8894 * opt , // Current option character
8995 * csrfile = NULL , // Certificste signing request filename
9096 * root_name = NULL , // Name of root certificate
@@ -356,14 +362,22 @@ main(int argc, // I - Number of command-line arguments
356362 {
357363 arg = argv [i ];
358364 }
365+ else if (!crtfile && !strcmp (command , "install" ))
366+ {
367+ crtfile = argv [i ];
368+ }
369+ else if (!keyfile && !strcmp (command , "install" ))
370+ {
371+ keyfile = argv [i ];
372+ }
359373 else
360374 {
361375 cupsLangPrintf (stderr , _ ("%s: Unknown option '%s'." ), "cups-x509" , argv [i ]);
362376 return (usage (stderr ));
363377 }
364378 }
365379
366- if (!command || !arg )
380+ if (!command || !arg || (! strcmp ( command , "install" ) && ! crtfile ) )
367381 {
368382 cupsLangPuts (stderr , _ ("cups-x509: Missing sub-command argument." ));
369383 return (usage (stderr ));
@@ -390,6 +404,10 @@ main(int argc, // I - Number of command-line arguments
390404 {
391405 return (do_csr (purpose , type , keyusage , organization , org_unit , locality , state , country , arg , num_alt_names , alt_names ));
392406 }
407+ else if (!strcmp (command , "install" ))
408+ {
409+ return (do_install (arg , crtfile , keyfile ));
410+ }
393411 else if (!strcmp (command , "server" ))
394412 {
395413 return (do_server (arg ));
@@ -645,6 +663,41 @@ do_csr(
645663}
646664
647665
666+ //
667+ // 'do_install()' - Install a certificate.
668+ //
669+
670+ static int // O - Exit status
671+ do_install (const char * common_name , // I - Common name
672+ const char * crtfile , // I - Certificate filename
673+ const char * keyfile ) // I - Private key filename or `NULL` if none
674+ {
675+ int ret = 1 ; // Exit status
676+ char * crt , // Certificate string
677+ * key ; // Private key string
678+
679+
680+ // Load the certificate and key, as needed...
681+ crt = get_file (crtfile );
682+ key = keyfile ? get_file (keyfile ) : NULL ;
683+
684+ if (!crt || (keyfile && !key ))
685+ goto done ;
686+
687+ // Try saving them...
688+ if (cupsSaveCredentials (/*path*/ NULL , common_name , crt , key ))
689+ ret = 0 ;
690+
691+ // Free and return...
692+ done :
693+
694+ free (crt );
695+ free (key );
696+
697+ return (ret );
698+ }
699+
700+
648701//
649702// 'do_server()' - Test running a server.
650703//
@@ -834,6 +887,64 @@ do_show(const char *common_name) // I - Common name
834887}
835888
836889
890+ //
891+ // 'get_file()' - Load a file into a string.
892+ //
893+ // Note: The string must be freed by the caller.
894+ //
895+
896+ static char * // O - String or `NULL` on error
897+ get_file (const char * filename ) // I - File to load
898+ {
899+ int fd ; // File descriptor
900+ struct stat info ; // File information
901+ char * file = NULL ; // File string
902+
903+
904+ if ((fd = open (filename , O_RDONLY )) < 0 )
905+ {
906+ cupsLangPrintf (stderr , _ ("%s: Unable to open '%s': %s" ), "cups-x509" , filename , strerror (errno ));
907+ return (NULL );
908+ }
909+
910+ if (fstat (fd , & info ))
911+ {
912+ cupsLangPrintf (stderr , _ ("%s: Unable to access '%s': %s" ), "cups-x509" , filename , strerror (errno ));
913+ goto error ;
914+ }
915+
916+ if (info .st_size > 65536 )
917+ {
918+ cupsLangPrintf (stderr , _ ("%s: File '%s' is too large to load in memory." ), "cups-x509" , filename );
919+ goto error ;
920+ }
921+
922+ if ((file = calloc (1 , (size_t )info .st_size + 1 )) == NULL )
923+ {
924+ cupsLangPrintf (stderr , _ ("%s: Unable to allocate memory for '%s': %s" ), "cups-x509" , filename , strerror (errno ));
925+ goto error ;
926+ }
927+
928+ if (read (fd , file , (size_t )info .st_size ) < 0 )
929+ {
930+ cupsLangPrintf (stderr , _ ("%s: Unable to read '%s': %s" ), "cups-x509" , filename , strerror (errno ));
931+ goto error ;
932+ }
933+
934+ close (fd );
935+
936+ return (file );
937+
938+ // If we get here something bad happened.
939+ error :
940+
941+ free (file );
942+ close (fd );
943+
944+ return (NULL );
945+ }
946+
947+
837948//
838949// 'usage()' - Show program usage...
839950//
@@ -845,13 +956,15 @@ usage(FILE *out) // I - Output file (stdout or stderr)
845956 cupsLangPuts (out , "" );
846957 cupsLangPuts (out , _ ("Sub-Commands:" ));
847958 cupsLangPuts (out , "" );
848- cupsLangPuts (out , _ ("ca COMMON-NAME Sign a CSR to produce a certificate." ));
849- cupsLangPuts (out , _ ("cacert COMMON-NAME Create a CA certificate." ));
850- cupsLangPuts (out , _ ("cert COMMON-NAME Create a certificate." ));
851- cupsLangPuts (out , _ ("client URI Connect to URI." ));
852- cupsLangPuts (out , _ ("csr COMMON-NAME Create a certificate signing request." ));
853- cupsLangPuts (out , _ ("server COMMON-NAME[:PORT] Run a HTTPS server (default port 8NNN.)" ));
854- cupsLangPuts (out , _ ("show COMMON-NAME Show stored credentials for COMMON-NAME." ));
959+ cupsLangPuts (out , _ ("ca COMMON-NAME Sign a CSR to produce a certificate." ));
960+ cupsLangPuts (out , _ ("cacert COMMON-NAME Create a CA certificate." ));
961+ cupsLangPuts (out , _ ("cert COMMON-NAME Create a certificate." ));
962+ cupsLangPuts (out , _ ("client URI Connect to URI." ));
963+ cupsLangPuts (out , _ ("csr COMMON-NAME Create a certificate signing request." ));
964+ cupsLangPuts (out , _ ("install COMMON-NAME FILENAME.crt [FILENAME.key]\n"
965+ " Install a certificate and (optional) private key." ));
966+ cupsLangPuts (out , _ ("server COMMON-NAME[:PORT] Run a HTTPS server (default port 8NNN.)" ));
967+ cupsLangPuts (out , _ ("show COMMON-NAME Show stored credentials for COMMON-NAME." ));
855968 cupsLangPuts (out , "" );
856969 cupsLangPuts (out , _ ("Options:" ));
857970 cupsLangPuts (out , _ ("" ));
0 commit comments