Coverage Report

Created: 2026-10-17 07:03

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/cups/cups/tls-openssl.c
Line
Count
Source
1
//
2
// TLS support code for CUPS using OpenSSL/LibreSSL.
3
//
4
// Note: This file is included from tls.c
5
//
6
// Copyright © 2020-2026 by OpenPrinting
7
// Copyright © 2007-2019 by Apple Inc.
8
// Copyright © 1997-2007 by Easy Software Products, all rights reserved.
9
//
10
// Licensed under Apache License v2.0.  See the file "LICENSE" for more
11
// information.
12
//
13
14
#include <openssl/x509v3.h>
15
#include <openssl/evp.h>
16
#include <openssl/objects.h>
17
#include <openssl/obj_mac.h>
18
19
20
//
21
// Local functions...
22
//
23
24
static long   http_bio_ctrl(BIO *h, int cmd, long arg1, void *arg2);
25
static int    http_bio_free(BIO *data);
26
static int    http_bio_new(BIO *h);
27
static int    http_bio_puts(BIO *h, const char *str);
28
static int    http_bio_read(BIO *h, char *buf, int size);
29
static int    http_bio_write(BIO *h, const char *buf, int num);
30
31
static bool   openssl_add_ext(STACK_OF(X509_EXTENSION) *exts, int nid, const char *value);
32
static X509_NAME  *openssl_create_name(const char *organization, const char *org_unit, const char *locality, const char *state_province, const char *country, const char *common_name, const char *email);
33
static EVP_PKEY   *openssl_create_key(cups_credtype_t type);
34
static X509_EXTENSION *openssl_create_san(const char *common_name, size_t num_alt_names, const char * const *alt_names);
35
static time_t   openssl_get_date(X509 *cert, int which);
36
//static void   openssl_load_crl(void);
37
static STACK_OF(X509 *) openssl_load_x509(const char *credentials);
38
static bool   openssl_validate_name(X509 *cert, const char *common_name);
39
40
41
//
42
// Local globals...
43
//
44
45
static BIO_METHOD *tls_bio_method = NULL;
46
          // OpenSSL BIO method
47
static const char * const tls_purpose_oids[] =
48
{         // OIDs for each key purpose value
49
  "1.3.6.1.5.5.7.3.1",      // serverAuth
50
  "1.3.6.1.5.5.7.3.2",      // clientAuth
51
  "1.3.6.1.5.5.7.3.3",      // codeSigning
52
  "1.3.6.1.5.5.7.3.4",      // emailProtection
53
  "1.3.6.1.5.5.7.3.8",      // timeStamping
54
  "1.3.6.1.5.5.7.3.9"     // OCSPSigning
55
};
56
static const char * const tls_usage_strings[] =
57
{         // Strings for each key usage value
58
  "digitalSignature",
59
  "nonRepudiation",
60
  "keyEncipherment",
61
  "dataEncipherment",
62
  "keyAgreement",
63
  "keyCertSign",
64
  "cRLSign",
65
  "encipherOnly",
66
  "decipherOnly"
67
};
68
69
70
//
71
// 'cupsAreCredentialsValidForName()' - Return whether the credentials are valid
72
//                                      for the given name.
73
//
74
75
bool          // O - `true` if valid, `false` otherwise
76
cupsAreCredentialsValidForName(
77
    const char *common_name,    // I - Name to check
78
    const char *credentials)    // I - Credentials
79
0
{
80
0
  STACK_OF(X509)  *certs;   // Certificate chain
81
0
  bool      result = false;  // Result
82
83
84
0
  DEBUG_printf("cupsAreCredentialsValidForName(common_name=\"%s\", credentials=\"%s\")", common_name, credentials);
85
86
  // Range check input...
87
0
  if (!common_name || !credentials)
88
0
    return (false);
89
90
  // Load the credentials...
91
0
  if ((certs = openssl_load_x509(credentials)) != NULL)
92
0
  {
93
    // Check the hostname against the primary certificate...
94
0
    result = openssl_validate_name(sk_X509_value(certs, 0), common_name);
95
96
0
    sk_X509_free(certs);
97
0
  }
98
99
0
  return (result);
100
0
}
101
102
103
//
104
// 'cupsCreateCredentials()' - Make an X.509 certificate and private key pair.
105
//
106
// This function creates an X.509 certificate and private key pair.  The
107
// certificate and key are stored in the directory "path" or, if "path" is
108
// `NULL`, in a per-user or system-wide (when running as root) certificate/key
109
// store.  The generated certificate is signed by the named root certificate or,
110
// if "root_name" is `NULL`, a site-wide default root certificate.  When
111
// "root_name" is `NULL` and there is no site-wide default root certificate, a
112
// self-signed certificate is generated instead.
113
//
114
// The "ca_cert" argument specifies whether a CA certificate should be created.
115
//
116
// The "purpose" argument specifies the purpose(s) used for the credentials as a
117
// bitwise OR of the following constants:
118
//
119
// - `CUPS_CREDPURPOSE_SERVER_AUTH` for validating TLS servers,
120
// - `CUPS_CREDPURPOSE_CLIENT_AUTH` for validating TLS clients,
121
// - `CUPS_CREDPURPOSE_CODE_SIGNING` for validating compiled code,
122
// - `CUPS_CREDPURPOSE_EMAIL_PROTECTION` for validating email messages,
123
// - `CUPS_CREDPURPOSE_TIME_STAMPING` for signing timestamps to objects, and/or
124
// - `CUPS_CREDPURPOSE_OCSP_SIGNING` for Online Certificate Status Protocol
125
//   message signing.
126
//
127
// The "type" argument specifies the type of credentials using one of the
128
// following constants:
129
//
130
// - `CUPS_CREDTYPE_DEFAULT`: default type (RSA-3072 or P-384),
131
// - `CUPS_CREDTYPE_RSA_2048_SHA256`: RSA with 2048-bit keys and SHA-256 hash,
132
// - `CUPS_CREDTYPE_RSA_3072_SHA256`: RSA with 3072-bit keys and SHA-256 hash,
133
// - `CUPS_CREDTYPE_RSA_4096_SHA256`: RSA with 4096-bit keys and SHA-256 hash,
134
// - `CUPS_CREDTYPE_ECDSA_P256_SHA256`: ECDSA using the P-256 curve with SHA-256 hash,
135
// - `CUPS_CREDTYPE_ECDSA_P384_SHA256`: ECDSA using the P-384 curve with SHA-256 hash, or
136
// - `CUPS_CREDTYPE_ECDSA_P521_SHA256`: ECDSA using the P-521 curve with SHA-256 hash.
137
//
138
// The "usage" argument specifies the usage(s) for the credentials as a bitwise
139
// OR of the following constants:
140
//
141
// - `CUPS_CREDUSAGE_DIGITAL_SIGNATURE`: digital signatures,
142
// - `CUPS_CREDUSAGE_NON_REPUDIATION`: non-repudiation/content commitment,
143
// - `CUPS_CREDUSAGE_KEY_ENCIPHERMENT`: key encipherment,
144
// - `CUPS_CREDUSAGE_DATA_ENCIPHERMENT`: data encipherment,
145
// - `CUPS_CREDUSAGE_KEY_AGREEMENT`: key agreement,
146
// - `CUPS_CREDUSAGE_KEY_CERT_SIGN`: key certicate signing,
147
// - `CUPS_CREDUSAGE_CRL_SIGN`: certificate revocation list signing,
148
// - `CUPS_CREDUSAGE_ENCIPHER_ONLY`: encipherment only,
149
// - `CUPS_CREDUSAGE_DECIPHER_ONLY`: decipherment only,
150
// - `CUPS_CREDUSAGE_DEFAULT_CA`: defaults for CA certificates,
151
// - `CUPS_CREDUSAGE_DEFAULT_TLS`: defaults for TLS certificates, and/or
152
// - `CUPS_CREDUSAGE_ALL`: all usages.
153
//
154
// The "organization", "org_unit", "locality", "state_province", and "country"
155
// arguments specify information about the identity and geolocation of the
156
// issuer.
157
//
158
// The "common_name" argument specifies the common name and the "num_alt_names"
159
// and "alt_names" arguments specify a list of DNS hostnames for the
160
// certificate.
161
//
162
// The "expiration_date" argument specifies the expiration date and time as a
163
// Unix `time_t` value in seconds.
164
//
165
166
bool          // O - `true` on success, `false` on failure
167
cupsCreateCredentials(
168
    const char         *path,   // I - Directory path for certificate/key store or `NULL` for default
169
    bool               ca_cert,   // I - `true` to create a CA certificate, `false` for a client/server certificate
170
    cups_credpurpose_t purpose,   // I - Credential purposes
171
    cups_credtype_t    type,    // I - Credential type
172
    cups_credusage_t   usage,   // I - Credential usages
173
    const char         *organization, // I - Organization or `NULL` to use common name
174
    const char         *org_unit, // I - Organizational unit or `NULL` for none
175
    const char         *locality, // I - City/town or `NULL` for "Unknown"
176
    const char         *state_province, // I - State/province or `NULL` for "Unknown"
177
    const char         *country,  // I - Country or `NULL` for locale-based default
178
    const char         *common_name,  // I - Common name
179
    const char         *email,    // I - Email address or `NULL` for none
180
    size_t             num_alt_names, // I - Number of subject alternate names
181
    const char * const *alt_names,  // I - Subject Alternate Names
182
    const char         *root_name,  // I - Root certificate/domain name or `NULL` for site/self-signed
183
    time_t             expiration_date) // I - Expiration date
184
0
{
185
0
  bool    result = false;    // Return value
186
0
  EVP_PKEY  *pkey;      // Key pair
187
0
  X509    *cert;      // Certificate
188
0
  X509    *root_cert = NULL; // Root certificate, if any
189
0
  EVP_PKEY  *root_key = NULL; // Root private key, if any
190
0
  char    defpath[1024],    // Default path
191
0
    crtfile[1024],    // Certificate filename
192
0
    keyfile[1024],    // Private key filename
193
0
    pubfile[1024],    // Public key filename
194
0
    root_crtfile[1024], // Root certificate filename
195
0
    root_keyfile[1024]; // Root private key filename
196
0
  time_t  curtime;    // Current time
197
0
  X509_NAME *name;      // Subject/issuer name
198
0
  ASN1_INTEGER  *serial;    // Serial number
199
0
  ASN1_TIME *notBefore,   // Initial date
200
0
    *notAfter;    // Expiration date
201
0
  BIO   *bio;     // Output file
202
0
  char    temp[1024],   // Temporary string
203
0
    *tempptr;   // Pointer into temporary string
204
0
  STACK_OF(X509_EXTENSION) *exts; // Extensions
205
0
  X509_EXTENSION *ext;      // Current extension
206
0
  unsigned  i;      // Looping var
207
0
  cups_credpurpose_t purpose_bit; // Current purpose
208
0
  cups_credusage_t usage_bit;   // Current usage
209
210
211
0
  DEBUG_printf("cupsCreateCredentials(path=\"%s\", ca_cert=%s, purpose=0x%x, type=%d, usage=0x%x, organization=\"%s\", org_unit=\"%s\", locality=\"%s\", state_province=\"%s\", country=\"%s\", common_name=\"%s\", num_alt_names=%u, alt_names=%p, root_name=\"%s\", expiration_date=%ld)", path, ca_cert ? "true" : "false", purpose, type, usage, organization, org_unit, locality, state_province, country, common_name, (unsigned)num_alt_names, (void *)alt_names, root_name, (long)expiration_date);
212
213
  // Filenames...
214
0
  if (!path)
215
0
    path = http_default_path(defpath, sizeof(defpath));
216
217
0
  if (!path || !common_name || !*common_name)
218
0
  {
219
0
    _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(EINVAL), 0);
220
0
    return (false);
221
0
  }
222
223
  // Create the encryption key...
224
0
  DEBUG_puts("1cupsCreateCredentials: Creating key pair.");
225
226
0
  if ((pkey = openssl_create_key(type)) == NULL)
227
0
    return (false);
228
229
0
  DEBUG_puts("1cupsCreateCredentials: Key pair created.");
230
231
  // Create the X.509 certificate...
232
0
  DEBUG_puts("1cupsCreateCredentials: Generating X.509 certificate.");
233
234
0
  if ((cert = X509_new()) == NULL)
235
0
  {
236
0
    EVP_PKEY_free(pkey);
237
0
    _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Unable to create X.509 certificate."), 1);
238
0
    return (false);
239
0
  }
240
241
0
  curtime = time(NULL);
242
243
0
  notBefore = ASN1_TIME_new();
244
0
  ASN1_TIME_set(notBefore, curtime);
245
0
  X509_set_notBefore(cert, notBefore);
246
0
  ASN1_TIME_free(notBefore);
247
248
0
  notAfter = ASN1_TIME_new();
249
0
  ASN1_TIME_set(notAfter, expiration_date);
250
0
  X509_set_notAfter(cert, notAfter);
251
0
  ASN1_TIME_free(notAfter);
252
253
0
  serial = ASN1_INTEGER_new();
254
0
  ASN1_INTEGER_set(serial, (long)curtime);
255
0
  X509_set_serialNumber(cert, serial);
256
0
  ASN1_INTEGER_free(serial);
257
258
0
  X509_set_pubkey(cert, pkey);
259
260
0
  name = openssl_create_name(organization, org_unit, locality, state_province, country, common_name, email);
261
262
0
  X509_set_subject_name(cert, name);
263
264
  // Try loading a root certificate...
265
0
  http_make_path(root_crtfile, sizeof(root_crtfile), path, root_name ? root_name : "_site_", "crt");
266
0
  http_make_path(root_keyfile, sizeof(root_keyfile), path, root_name ? root_name : "_site_", "key");
267
268
0
  if (!ca_cert && !access(root_crtfile, 0) && !access(root_keyfile, 0))
269
0
  {
270
0
    if ((bio = BIO_new_file(root_crtfile, "rb")) != NULL)
271
0
    {
272
0
      PEM_read_bio_X509(bio, &root_cert, /*cb*/NULL, /*u*/NULL);
273
0
      BIO_free(bio);
274
275
0
      if ((bio = BIO_new_file(root_keyfile, "rb")) != NULL)
276
0
      {
277
0
  PEM_read_bio_PrivateKey(bio, &root_key, /*cb*/NULL, /*u*/NULL);
278
0
  BIO_free(bio);
279
0
      }
280
281
0
      if (!root_key)
282
0
      {
283
        // Only use root certificate if we have the key...
284
0
        X509_free(root_cert);
285
0
        root_cert = NULL;
286
0
      }
287
0
    }
288
289
0
    if (!root_cert || !root_key)
290
0
    {
291
0
      _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Unable to load X.509 CA certificate and private key."), 1);
292
0
      goto done;
293
0
    }
294
0
  }
295
296
0
  if (root_cert)
297
0
    X509_set_issuer_name(cert, X509_get_subject_name(root_cert));
298
0
  else
299
0
    X509_set_issuer_name(cert, name);
300
301
0
  X509_NAME_free(name);
302
303
0
  exts = sk_X509_EXTENSION_new_null();
304
305
0
  if (ca_cert)
306
0
  {
307
    // Add extensions that are required to make Chrome happy...
308
0
    openssl_add_ext(exts, NID_basic_constraints, "critical,CA:TRUE,pathlen:0");
309
0
  }
310
0
  else
311
0
  {
312
    // Add extension with DNS names and free buffer for GENERAL_NAME
313
0
    if ((ext = openssl_create_san(common_name, num_alt_names, alt_names)) == NULL)
314
0
      goto done;
315
316
0
    sk_X509_EXTENSION_push(exts, ext);
317
318
    // Add extensions that are required to make Chrome happy...
319
0
    openssl_add_ext(exts, NID_basic_constraints, "critical,CA:FALSE,pathlen:0");
320
0
  }
321
322
0
  cupsCopyString(temp, "critical", sizeof(temp));
323
0
  for (tempptr = temp + strlen(temp), i = 0, usage_bit = CUPS_CREDUSAGE_DIGITAL_SIGNATURE; i < (sizeof(tls_usage_strings) / sizeof(tls_usage_strings[0])); i ++, usage_bit *= 2)
324
0
  {
325
0
    if (!(usage & usage_bit))
326
0
      continue;
327
328
0
    snprintf(tempptr, sizeof(temp) - (size_t)(tempptr - temp), ",%s", tls_usage_strings[i]);
329
330
0
    tempptr += strlen(tempptr);
331
0
  }
332
0
  openssl_add_ext(exts, NID_key_usage, temp);
333
334
0
  temp[0] = '\0';
335
0
  for (tempptr = temp, i = 0, purpose_bit = CUPS_CREDPURPOSE_SERVER_AUTH; i < (sizeof(tls_purpose_oids) / sizeof(tls_purpose_oids[0])); i ++, purpose_bit *= 2)
336
0
  {
337
0
    if (!(purpose & purpose_bit))
338
0
      continue;
339
340
0
    if (tempptr == temp)
341
0
      cupsCopyString(temp, tls_purpose_oids[i], sizeof(temp));
342
0
    else
343
0
      snprintf(tempptr, sizeof(temp) - (size_t)(tempptr - temp), ",%s", tls_purpose_oids[i]);
344
345
0
    tempptr += strlen(tempptr);
346
0
  }
347
0
  openssl_add_ext(exts, NID_ext_key_usage, temp);
348
349
0
  openssl_add_ext(exts, NID_subject_key_identifier, "hash");
350
0
  openssl_add_ext(exts, NID_authority_key_identifier, "keyid,issuer");
351
352
0
  while ((ext = sk_X509_EXTENSION_pop(exts)) != NULL)
353
0
  {
354
0
    if (!X509_add_ext(cert, ext, -1))
355
0
    {
356
0
      sk_X509_EXTENSION_pop_free(exts, X509_EXTENSION_free);
357
0
      goto done;
358
0
    }
359
0
  }
360
361
0
  X509_set_version(cert, 2); // v3
362
363
0
  if (root_key)
364
0
    X509_sign(cert, root_key, EVP_sha256());
365
0
  else
366
0
    X509_sign(cert, pkey, EVP_sha256());
367
368
  // Save them...
369
0
  http_make_path(crtfile, sizeof(crtfile), path, common_name, "crt");
370
0
  http_make_path(keyfile, sizeof(keyfile), path, common_name, "key");
371
0
  http_make_path(pubfile, sizeof(pubfile), path, common_name, "pub");
372
373
0
  if ((bio = BIO_new_file(keyfile, "wb")) == NULL)
374
0
  {
375
0
    _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(errno), 0);
376
0
    goto done;
377
0
  }
378
379
0
  if (!PEM_write_bio_PrivateKey(bio, pkey, NULL, NULL, 0, NULL, NULL))
380
0
  {
381
0
    _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Unable to write private key."), 1);
382
0
    BIO_free(bio);
383
0
    goto done;
384
0
  }
385
386
0
  BIO_free(bio);
387
388
0
  if ((bio = BIO_new_file(pubfile, "wb")) == NULL)
389
0
  {
390
0
    _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(errno), 0);
391
0
    goto done;
392
0
  }
393
394
0
  if (!PEM_write_bio_PUBKEY(bio, pkey))
395
0
  {
396
0
    _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Unable to write public key."), true);
397
0
    BIO_free(bio);
398
0
    goto done;
399
0
  }
400
401
0
  BIO_free(bio);
402
403
0
  if ((bio = BIO_new_file(crtfile, "wb")) == NULL)
404
0
  {
405
0
    _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(errno), 0);
406
0
    goto done;
407
0
  }
408
409
0
  if (!PEM_write_bio_X509(bio, cert))
410
0
  {
411
0
    _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Unable to write X.509 certificate."), 1);
412
0
    BIO_free(bio);
413
0
    goto done;
414
0
  }
415
416
0
  if (root_cert)
417
0
    PEM_write_bio_X509(bio, root_cert);
418
419
0
  BIO_free(bio);
420
421
0
  result = true;
422
0
  DEBUG_puts("1cupsCreateCredentials: Successfully created credentials.");
423
424
  // Cleanup...
425
0
  done:
426
427
0
  X509_free(cert);
428
0
  EVP_PKEY_free(pkey);
429
430
0
  if (root_cert)
431
0
    X509_free(root_cert);
432
0
  if (root_key)
433
0
    EVP_PKEY_free(root_key);
434
435
0
  return (result);
436
0
}
437
438
439
//
440
// 'cupsCreateCredentialsRequest()' - Make an X.509 Certificate Signing Request.
441
//
442
// This function creates an X.509 certificate signing request (CSR) and
443
// associated private key.  The CSR and key are stored in the directory "path"
444
// or, if "path" is `NULL`, in a per-user or system-wide (when running as root)
445
// certificate/key store.
446
//
447
// The "purpose" argument specifies the purpose(s) used for the credentials as a
448
// bitwise OR of the following constants:
449
//
450
// - `CUPS_CREDPURPOSE_SERVER_AUTH` for validating TLS servers,
451
// - `CUPS_CREDPURPOSE_CLIENT_AUTH` for validating TLS clients,
452
// - `CUPS_CREDPURPOSE_CODE_SIGNING` for validating compiled code,
453
// - `CUPS_CREDPURPOSE_EMAIL_PROTECTION` for validating email messages,
454
// - `CUPS_CREDPURPOSE_TIME_STAMPING` for signing timestamps to objects, and/or
455
// - `CUPS_CREDPURPOSE_OCSP_SIGNING` for Online Certificate Status Protocol
456
//   message signing.
457
//
458
// The "type" argument specifies the type of credentials using one of the
459
// following constants:
460
//
461
// - `CUPS_CREDTYPE_DEFAULT`: default type (RSA-3072 or P-384),
462
// - `CUPS_CREDTYPE_RSA_2048_SHA256`: RSA with 2048-bit keys and SHA-256 hash,
463
// - `CUPS_CREDTYPE_RSA_3072_SHA256`: RSA with 3072-bit keys and SHA-256 hash,
464
// - `CUPS_CREDTYPE_RSA_4096_SHA256`: RSA with 4096-bit keys and SHA-256 hash,
465
// - `CUPS_CREDTYPE_ECDSA_P256_SHA256`: ECDSA using the P-256 curve with SHA-256 hash,
466
// - `CUPS_CREDTYPE_ECDSA_P384_SHA256`: ECDSA using the P-384 curve with SHA-256 hash, or
467
// - `CUPS_CREDTYPE_ECDSA_P521_SHA256`: ECDSA using the P-521 curve with SHA-256 hash.
468
//
469
// The "usage" argument specifies the usage(s) for the credentials as a bitwise
470
// OR of the following constants:
471
//
472
// - `CUPS_CREDUSAGE_DIGITAL_SIGNATURE`: digital signatures,
473
// - `CUPS_CREDUSAGE_NON_REPUDIATION`: non-repudiation/content commitment,
474
// - `CUPS_CREDUSAGE_KEY_ENCIPHERMENT`: key encipherment,
475
// - `CUPS_CREDUSAGE_DATA_ENCIPHERMENT`: data encipherment,
476
// - `CUPS_CREDUSAGE_KEY_AGREEMENT`: key agreement,
477
// - `CUPS_CREDUSAGE_KEY_CERT_SIGN`: key certicate signing,
478
// - `CUPS_CREDUSAGE_CRL_SIGN`: certificate revocation list signing,
479
// - `CUPS_CREDUSAGE_ENCIPHER_ONLY`: encipherment only,
480
// - `CUPS_CREDUSAGE_DECIPHER_ONLY`: decipherment only,
481
// - `CUPS_CREDUSAGE_DEFAULT_CA`: defaults for CA certificates,
482
// - `CUPS_CREDUSAGE_DEFAULT_TLS`: defaults for TLS certificates, and/or
483
// - `CUPS_CREDUSAGE_ALL`: all usages.
484
//
485
// The "organization", "org_unit", "locality", "state_province", and "country"
486
// arguments specify information about the identity and geolocation of the
487
// issuer.
488
//
489
// The "common_name" argument specifies the common name and the "num_alt_names"
490
// and "alt_names" arguments specify a list of DNS hostnames for the
491
// certificate.
492
//
493
494
bool          // O - `true` on success, `false` on error
495
cupsCreateCredentialsRequest(
496
    const char         *path,   // I - Directory path for certificate/key store or `NULL` for default
497
    cups_credpurpose_t purpose,   // I - Credential purposes
498
    cups_credtype_t    type,    // I - Credential type
499
    cups_credusage_t   usage,   // I - Credential usages
500
    const char         *organization, // I - Organization or `NULL` to use common name
501
    const char         *org_unit, // I - Organizational unit or `NULL` for none
502
    const char         *locality, // I - City/town or `NULL` for "Unknown"
503
    const char         *state_province, // I - State/province or `NULL` for "Unknown"
504
    const char         *country,  // I - Country or `NULL` for locale-based default
505
    const char         *common_name,  // I - Common name
506
    const char         *email,    // I - Email address or `NULL` for none
507
    size_t             num_alt_names, // I - Number of subject alternate names
508
    const char * const *alt_names)  // I - Subject Alternate Names
509
0
{
510
0
  bool    ret = false;    // Return value
511
0
  EVP_PKEY  *pkey;      // Key pair
512
0
  X509_REQ  *csr;     // Certificate signing request
513
0
  X509_NAME *name;      // Subject/issuer name
514
0
  X509_EXTENSION *ext;      // X509 extension
515
0
  BIO   *bio;     // Output file
516
0
  char    temp[1024],   // Temporary directory name
517
0
    *tempptr,   // Pointer into temporary string
518
0
    csrfile[1024],    // Certificate signing request filename
519
0
    keyfile[1024],    // Private key filename
520
0
    pubfile[1024];    // Public key filename
521
0
  STACK_OF(X509_EXTENSION) *exts; // Extensions
522
0
  unsigned  i;      // Looping var
523
0
  cups_credpurpose_t purpose_bit; // Current purpose
524
0
  cups_credusage_t usage_bit;   // Current usage
525
526
527
0
  DEBUG_printf("cupsCreateCredentialsRequest(path=\"%s\", purpose=0x%x, type=%d, usage=0x%x, organization=\"%s\", org_unit=\"%s\", locality=\"%s\", state_province=\"%s\", country=\"%s\", common_name=\"%s\", num_alt_names=%u, alt_names=%p)", path, purpose, type, usage, organization, org_unit, locality, state_province, country, common_name, (unsigned)num_alt_names, (void *)alt_names);
528
529
  // Filenames...
530
0
  if (!path)
531
0
    path = http_default_path(temp, sizeof(temp));
532
533
0
  if (!path || !common_name || !*common_name)
534
0
  {
535
0
    _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(EINVAL), 0);
536
0
    return (false);
537
0
  }
538
539
0
  http_make_path(csrfile, sizeof(csrfile), path, common_name, "csr");
540
0
  http_make_path(keyfile, sizeof(keyfile), path, common_name, "ktm");
541
0
  http_make_path(pubfile, sizeof(pubfile), path, common_name, "pub");
542
543
  // Create the encryption key...
544
0
  DEBUG_puts("1cupsCreateCredentialsRequest: Creating key pair.");
545
546
0
  if ((pkey = openssl_create_key(type)) == NULL)
547
0
    return (false);
548
549
0
  DEBUG_puts("1cupsCreateCredentialsRequest: Key pair created.");
550
551
  // Create the X.509 certificate...
552
0
  DEBUG_puts("1cupsCreateCredentialsRequest: Generating self-signed X.509 certificate.");
553
554
0
  if ((csr = X509_REQ_new()) == NULL)
555
0
  {
556
0
    _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Unable to create X.509 certificate signing request."), 1);
557
0
    goto done;
558
0
  }
559
560
0
  X509_REQ_set_pubkey(csr, pkey);
561
562
0
  if ((name = openssl_create_name(organization, org_unit, locality, state_province, country, common_name, email)) == NULL)
563
0
    goto done;
564
565
0
  X509_REQ_set_subject_name(csr, name);
566
0
  X509_NAME_free(name);
567
568
  // Add extension with DNS names and free buffer for GENERAL_NAME
569
0
  exts = sk_X509_EXTENSION_new_null();
570
571
0
  if ((ext = openssl_create_san(common_name, num_alt_names, alt_names)) == NULL)
572
0
    goto done;
573
574
0
  sk_X509_EXTENSION_push(exts, ext);
575
576
0
  cupsCopyString(temp, "critical", sizeof(temp));
577
0
  for (tempptr = temp + strlen(temp), i = 0, usage_bit = CUPS_CREDUSAGE_DIGITAL_SIGNATURE; i < (sizeof(tls_usage_strings) / sizeof(tls_usage_strings[0])); i ++, usage_bit *= 2)
578
0
  {
579
0
    if (!(usage & usage_bit))
580
0
      continue;
581
582
0
    snprintf(tempptr, sizeof(temp) - (size_t)(tempptr - temp), ",%s", tls_usage_strings[i]);
583
584
0
    tempptr += strlen(tempptr);
585
0
  }
586
0
  openssl_add_ext(exts, NID_key_usage, temp);
587
588
0
  temp[0] = '\0';
589
0
  for (tempptr = temp, i = 0, purpose_bit = CUPS_CREDPURPOSE_SERVER_AUTH; i < (sizeof(tls_purpose_oids) / sizeof(tls_purpose_oids[0])); i ++, purpose_bit *= 2)
590
0
  {
591
0
    if (!(purpose & purpose_bit))
592
0
      continue;
593
594
0
    if (tempptr == temp)
595
0
      cupsCopyString(temp, tls_purpose_oids[i], sizeof(temp));
596
0
    else
597
0
      snprintf(tempptr, sizeof(temp) - (size_t)(tempptr - temp), ",%s", tls_purpose_oids[i]);
598
599
0
    tempptr += strlen(tempptr);
600
0
  }
601
0
  openssl_add_ext(exts, NID_ext_key_usage, temp);
602
603
0
  X509_REQ_add_extensions(csr, exts);
604
0
  X509_REQ_sign(csr, pkey, EVP_sha256());
605
606
0
  sk_X509_EXTENSION_pop_free(exts, X509_EXTENSION_free);
607
608
  // Save them...
609
0
  if ((bio = BIO_new_file(keyfile, "wb")) == NULL)
610
0
  {
611
0
    _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(errno), 0);
612
0
    goto done;
613
0
  }
614
615
0
  if (!PEM_write_bio_PrivateKey(bio, pkey, NULL, NULL, 0, NULL, NULL))
616
0
  {
617
0
    _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Unable to write private key."), 1);
618
0
    BIO_free(bio);
619
0
    goto done;
620
0
  }
621
622
0
  BIO_free(bio);
623
624
0
  if ((bio = BIO_new_file(pubfile, "wb")) == NULL)
625
0
  {
626
0
    _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(errno), 0);
627
0
    goto done;
628
0
  }
629
630
0
  if (!PEM_write_bio_PUBKEY(bio, pkey))
631
0
  {
632
0
    _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Unable to write public key."), true);
633
0
    BIO_free(bio);
634
0
    goto done;
635
0
  }
636
637
0
  BIO_free(bio);
638
639
0
  if ((bio = BIO_new_file(csrfile, "wb")) == NULL)
640
0
  {
641
0
    _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(errno), 0);
642
0
    goto done;
643
0
  }
644
645
0
  if (!PEM_write_bio_X509_REQ(bio, csr))
646
0
  {
647
0
    _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Unable to write X.509 certificate signing request."), 1);
648
0
    BIO_free(bio);
649
0
    goto done;
650
0
  }
651
652
0
  BIO_free(bio);
653
654
0
  ret = true;
655
0
  DEBUG_puts("1cupsCreateCredentialsRequest: Successfully created signing request.");
656
657
  // Cleanup...
658
0
  done:
659
660
0
  X509_REQ_free(csr);
661
0
  EVP_PKEY_free(pkey);
662
663
0
  return (ret);
664
0
}
665
666
667
//
668
// 'cupsGetCredentialsExpiration()' - Return the expiration date of the credentials.
669
//
670
671
time_t          // O - Expiration date of credentials
672
cupsGetCredentialsExpiration(
673
    const char *credentials)    // I - Credentials
674
0
{
675
0
  time_t    result = 0; // Result
676
0
  STACK_OF(X509)  *certs;   // Certificate chain
677
678
679
0
  if ((certs = openssl_load_x509(credentials)) != NULL)
680
0
  {
681
0
    result = openssl_get_date(sk_X509_value(certs, 0), 1);
682
0
    sk_X509_free(certs);
683
0
  }
684
685
0
  return (result);
686
0
}
687
688
689
//
690
// 'cupsGetCredentialsInfo()' - Return a string describing the credentials.
691
//
692
693
char *          // O - Credentials description or `NULL` on error
694
cupsGetCredentialsInfo(
695
    const char *credentials,    // I - Credentials
696
    char       *buffer,     // I - Buffer
697
    size_t     bufsize)     // I - Size of buffer
698
0
{
699
0
  STACK_OF(X509)  *certs;   // Certificate chain
700
0
  X509      *cert;    // Certificate
701
702
703
  // Range check input...
704
0
  DEBUG_printf("cupsGetCredentialsInfo(credentials=%p, buffer=%p, bufsize=" CUPS_LLFMT ")", (void *)credentials, (void *)buffer, CUPS_LLCAST bufsize);
705
706
0
  if (buffer)
707
0
    *buffer = '\0';
708
709
0
  if (!credentials || !buffer || bufsize < 32)
710
0
  {
711
0
    DEBUG_puts("1cupsGetCredentialsInfo: Returning NULL.");
712
0
    return (NULL);
713
0
  }
714
715
0
  if ((certs = openssl_load_x509(credentials)) != NULL)
716
0
  {
717
0
    char    name[256],  // Common name associated with cert
718
0
      issuer[256],  // Issuer associated with cert
719
0
      expdate[256]; // Expiration data as string
720
0
    time_t    expiration; // Expiration date of cert
721
0
    const char    *sigalg;  // Signature algorithm
722
0
    unsigned char md5_digest[16]; // MD5 result
723
724
0
    DEBUG_printf("2cupsGetCredentialsInfo: certs=%p(%d certificates)", certs, sk_X509_num(certs));
725
0
    cert = sk_X509_value(certs, 0);
726
0
    DEBUG_printf("2cupsGetCredentialsInfo: cert=%p", cert);
727
728
0
    if (X509_NAME_get_text_by_NID(X509_get_subject_name(cert), NID_commonName, name, sizeof(name)) < 0)
729
0
      cupsCopyString(name, "unknown", sizeof(name));
730
731
0
    if (X509_NAME_get_text_by_NID(X509_get_issuer_name(cert), NID_commonName, issuer, sizeof(issuer)) < 0)
732
0
      cupsCopyString(issuer, "unknown", sizeof(issuer));
733
734
0
    expiration = openssl_get_date(cert, 1);
735
736
0
    switch (X509_get_signature_nid(cert))
737
0
    {
738
0
      case NID_ecdsa_with_SHA1 :
739
0
          sigalg = "SHA1WithECDSAEncryption";
740
0
          break;
741
0
      case NID_ecdsa_with_SHA224 :
742
0
          sigalg = "SHA224WithECDSAEncryption";
743
0
          break;
744
0
      case NID_ecdsa_with_SHA256 :
745
0
          sigalg = "SHA256WithECDSAEncryption";
746
0
          break;
747
0
      case NID_ecdsa_with_SHA384 :
748
0
          sigalg = "SHA384WithECDSAEncryption";
749
0
          break;
750
0
      case NID_ecdsa_with_SHA512 :
751
0
          sigalg = "SHA512WithECDSAEncryption";
752
0
          break;
753
0
      case NID_sha1WithRSAEncryption :
754
0
          sigalg = "SHA1WithRSAEncryption";
755
0
          break;
756
0
      case NID_sha224WithRSAEncryption :
757
0
          sigalg = "SHA224WithRSAEncryption";
758
0
          break;
759
0
      case NID_sha256WithRSAEncryption :
760
0
          sigalg = "SHA256WithRSAEncryption";
761
0
          break;
762
0
      case NID_sha384WithRSAEncryption :
763
0
          sigalg = "SHA384WithRSAEncryption";
764
0
          break;
765
0
      case NID_sha512WithRSAEncryption :
766
0
          sigalg = "SHA512WithRSAEncryption";
767
0
          break;
768
0
      default :
769
0
          sigalg = "Unknown";
770
0
          break;
771
0
    }
772
773
0
    cupsHashData("md5", credentials, strlen(credentials), md5_digest, sizeof(md5_digest));
774
775
0
    snprintf(buffer, bufsize, "%s (issued by %s) / %s / %s / %02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X", name, issuer, httpGetDateString2(expiration, expdate, sizeof(expdate)), sigalg, md5_digest[0], md5_digest[1], md5_digest[2], md5_digest[3], md5_digest[4], md5_digest[5], md5_digest[6], md5_digest[7], md5_digest[8], md5_digest[9], md5_digest[10], md5_digest[11], md5_digest[12], md5_digest[13], md5_digest[14], md5_digest[15]);
776
0
    sk_X509_free(certs);
777
0
  }
778
779
0
  DEBUG_printf("1cupsGetCredentialsInfo: Returning \"%s\".", buffer);
780
781
0
  return (buffer);
782
0
}
783
784
785
//
786
// 'cupsGetCredentialsTrust()' - Return the trust of credentials.
787
//
788
// This function determines the level of trust for the supplied credentials.
789
// The "path" parameter specifies the certificate/key store for known
790
// credentials and certificate authorities.  The "common_name" parameter
791
// specifies the FQDN of the service being accessed such as
792
// "printer.example.com".  The "credentials" parameter provides the credentials
793
// being evaluated, which are usually obtained with the
794
// @link httpCopyPeerCredentials@ function.  The "require_ca" parameter
795
// specifies whether a CA-signed certificate is required for trust.
796
//
797
// The `AllowAnyRoot`, `AllowExpiredCerts`, `TrustOnFirstUse`, and
798
// `ValidateCerts` options in the "client.conf" file (or corresponding
799
// preferences file on macOS) control the trust policy, which defaults to
800
// AllowAnyRoot=Yes, AllowExpiredCerts=No, TrustOnFirstUse=Yes, and
801
// ValidateCerts=No.  When the "require_ca" parameter is `true` the AllowAnyRoot
802
// and TrustOnFirstUse policies are turned off ("No").
803
//
804
// The returned trust value can be one of the following:
805
//
806
// - `HTTP_TRUST_OK`: Credentials are OK/trusted
807
// - `HTTP_TRUST_INVALID`: Credentials are invalid
808
// - `HTTP_TRUST_EXPIRED`: Credentials are expired
809
// - `HTTP_TRUST_RENEWED`: Credentials have been renewed
810
// - `HTTP_TRUST_UNKNOWN`: Credentials are unknown/new
811
//
812
813
http_trust_t        // O - Level of trust
814
cupsGetCredentialsTrust(
815
    const char *path,     // I - Directory path for certificate/key store or `NULL` for default
816
    const char *common_name,    // I - Common name for trust lookup
817
    const char *credentials,    // I - Credentials
818
    bool       require_ca)    // I - Require a CA-signed certificate?
819
0
{
820
0
  http_trust_t    trust = HTTP_TRUST_OK;
821
          // Trusted?
822
0
  STACK_OF(X509)  *certs;   // Certificate chain
823
0
  X509      *cert;    // Certificate
824
0
  char      *tcreds = NULL; // Trusted credentials
825
0
  char      defpath[1024];  // Default path
826
0
  _cups_globals_t *cg = _cupsGlobals(); // Per-thread globals
827
828
829
0
  DEBUG_printf("cupsGetCredentialsTrust(path=\"%s\", common_name=\"%s\", credentials=\"%lu bytes\", require_ca=%s)", path, common_name, (unsigned long)(credentials ? strlen(credentials) : 0), require_ca ? "true" : "false");
830
831
  // Range check input...
832
0
  if (!path)
833
0
    path = http_default_path(defpath, sizeof(defpath));
834
835
0
  if (!path || !credentials || !common_name)
836
0
  {
837
0
    _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(EINVAL), false);
838
0
    DEBUG_printf("1cupsGetCredentialsTrust: Returning %d.", HTTP_TRUST_UNKNOWN);
839
0
    return (HTTP_TRUST_UNKNOWN);
840
0
  }
841
842
  // Load the credentials...
843
0
  if ((certs = openssl_load_x509(credentials)) == NULL)
844
0
  {
845
0
    _cupsSetError(IPP_STATUS_ERROR_CUPS_PKI, _("Unable to import credentials."), true);
846
0
    DEBUG_printf("1cupsGetCredentialsTrust: Returning %d.", HTTP_TRUST_UNKNOWN);
847
0
    return (HTTP_TRUST_UNKNOWN);
848
0
  }
849
850
0
  cert = sk_X509_shift(certs);
851
852
0
  if (!cg->client_conf_loaded)
853
0
  {
854
0
    _cupsSetDefaults();
855
//    openssl_load_crl();
856
0
  }
857
858
  // Look this common name up in the default keychains...
859
0
  if (sk_X509_num(certs) == 0 && (tcreds = cupsCopyCredentials(path, common_name)) != NULL)
860
0
  {
861
0
    char  credentials_str[1024],  // String for incoming credentials
862
0
    tcreds_str[1024]; // String for saved credentials
863
864
0
    cupsGetCredentialsInfo(credentials, credentials_str, sizeof(credentials_str));
865
0
    cupsGetCredentialsInfo(tcreds, tcreds_str, sizeof(tcreds_str));
866
867
0
    if (strcmp(credentials_str, tcreds_str))
868
0
    {
869
      // Credentials don't match, let's look at the expiration date of the new
870
      // credentials and allow if the new ones have a later expiration...
871
0
      time_t tcreds_exp = cupsGetCredentialsExpiration(tcreds);
872
          // Expiration of saved credentials
873
874
0
      if (!cg->trust_first || require_ca)
875
0
      {
876
        // Do not trust certificates on first use...
877
0
        _cupsSetError(IPP_STATUS_ERROR_CUPS_PKI, _("Trust on first use is disabled."), 1);
878
879
0
        trust = HTTP_TRUST_INVALID;
880
0
      }
881
0
      else if (openssl_get_date(cert, 1) <= tcreds_exp)
882
0
      {
883
        // The new credentials are not newly issued...
884
0
        _cupsSetError(IPP_STATUS_ERROR_CUPS_PKI, _("New credentials are older than stored credentials."), 1);
885
886
0
        trust = HTTP_TRUST_INVALID;
887
0
      }
888
0
      else if (!cupsAreCredentialsValidForName(common_name, credentials))
889
0
      {
890
        // The common name does not match the issued certificate...
891
0
        _cupsSetError(IPP_STATUS_ERROR_CUPS_PKI, _("New credentials are not valid for name."), 1);
892
893
0
        trust = HTTP_TRUST_INVALID;
894
0
      }
895
0
      else if (tcreds_exp < time(NULL))
896
0
      {
897
        // Save the renewed credentials...
898
0
  trust = HTTP_TRUST_RENEWED;
899
900
0
        cupsSaveCredentials(path, common_name, credentials, NULL);
901
0
      }
902
0
    }
903
904
0
    free(tcreds);
905
0
  }
906
0
  else if ((cg->validate_certs || require_ca) && !cupsAreCredentialsValidForName(common_name, credentials))
907
0
  {
908
0
    _cupsSetError(IPP_STATUS_ERROR_CUPS_PKI, _("No stored credentials, not valid for name."), 1);
909
0
    trust = HTTP_TRUST_INVALID;
910
0
  }
911
0
  else if (sk_X509_num(certs) > 0)
912
0
  {
913
0
    trust = HTTP_TRUST_INVALID;
914
915
0
    if ((tcreds = http_check_roots(credentials)) != NULL)
916
0
    {
917
0
      trust = HTTP_TRUST_OK;
918
0
    }
919
0
    else
920
0
    {
921
      // See if we have a site CA certificate we can compare...
922
0
      if ((tcreds = cupsCopyCredentials(path, "_site_")) != NULL)
923
0
      {
924
0
  size_t  credslen,   // Length of credentials
925
0
    tcredslen;    // Length of trust root
926
927
  // Do a tail comparison of the root...
928
0
  credslen  = strlen(credentials);
929
0
  tcredslen = strlen(tcreds);
930
0
  if (credslen > tcredslen && !strcmp(credentials + (credslen - tcredslen), tcreds))
931
0
  {
932
    // Certificate is signed by the site CA cert...
933
0
    trust = HTTP_TRUST_OK;
934
0
  }
935
0
      }
936
0
    }
937
938
0
    if (trust == HTTP_TRUST_OK && *tcreds)
939
0
    {
940
      // Verify the full certificate chain...
941
0
      STACK_OF(X509)  *tcerts = openssl_load_x509(tcreds);
942
          // Trusted certificates
943
0
      X509_STORE_CTX  *ctx = X509_STORE_CTX_new();
944
          // Context for certificate store
945
0
      X509_STORE  *store = X509_STORE_new();
946
          // Certificate store
947
948
0
      if (!tcerts || !ctx || !store)
949
0
      {
950
        // Unable to create store...
951
0
        trust = HTTP_TRUST_INVALID;
952
0
      }
953
0
      else
954
0
      {
955
        // Verify the certificate chain signatures against the trusted root...
956
0
        int i;      // Looping var
957
958
0
  for (i = 0; i < sk_X509_num(tcerts); i ++)
959
0
    X509_STORE_add_cert(store, sk_X509_value(tcerts, i));
960
961
0
  X509_STORE_CTX_init(ctx, store, cert, certs);
962
963
0
  if (X509_verify_cert(ctx) != 1)
964
0
    trust = HTTP_TRUST_INVALID;
965
0
      }
966
967
0
      if (ctx)
968
0
        X509_STORE_CTX_free(ctx);
969
0
      if (store)
970
0
        X509_STORE_free(store);
971
0
      if (tcerts)
972
0
        sk_X509_pop_free(tcerts, X509_free);
973
0
    }
974
975
0
    free(tcreds);
976
977
0
    if (trust != HTTP_TRUST_OK)
978
0
      _cupsSetError(IPP_STATUS_ERROR_CUPS_PKI, _("Credentials do not validate against CA certificates."), 1);
979
0
  }
980
0
  else if (require_ca)
981
0
  {
982
0
    _cupsSetError(IPP_STATUS_ERROR_CUPS_PKI, _("Credentials are not CA-signed."), 1);
983
0
    trust = HTTP_TRUST_INVALID;
984
0
  }
985
0
  else if (!cg->trust_first)
986
0
  {
987
0
    _cupsSetError(IPP_STATUS_ERROR_CUPS_PKI, _("Trust on first use is disabled."), 1);
988
0
    trust = HTTP_TRUST_INVALID;
989
0
  }
990
0
  else if (!cg->any_root || require_ca)
991
0
  {
992
0
    _cupsSetError(IPP_STATUS_ERROR_CUPS_PKI, _("Self-signed credentials are blocked."), 1);
993
0
    trust = HTTP_TRUST_INVALID;
994
0
  }
995
996
0
  if (trust == HTTP_TRUST_OK && !cg->expired_certs)
997
0
  {
998
0
    time_t  curtime;    // Current date/time
999
1000
0
    time(&curtime);
1001
1002
0
    DEBUG_printf("1cupsGetCredentialsTrust: curtime=" CUPS_LLFMT ", notBefore=" CUPS_LLFMT ", notAfter=" CUPS_LLFMT, CUPS_LLCAST curtime, CUPS_LLCAST openssl_get_date(cert, 0), CUPS_LLCAST openssl_get_date(cert, 1));
1003
1004
0
    if ((curtime + 86400) < openssl_get_date(cert, 0) || curtime > openssl_get_date(cert, 1))
1005
0
    {
1006
0
      _cupsSetError(IPP_STATUS_ERROR_CUPS_PKI, _("Credentials have expired."), 1);
1007
0
      trust = HTTP_TRUST_EXPIRED;
1008
0
    }
1009
0
  }
1010
1011
0
  sk_X509_free(certs);
1012
0
  X509_free(cert);
1013
1014
0
  DEBUG_printf("1cupsGetCredentialsTrust: Returning %d.", trust);
1015
1016
0
  return (trust);
1017
0
}
1018
1019
1020
//
1021
// 'cupsSignCredentialsRequest()' - Sign an X.509 certificate signing request to produce an X.509 certificate chain.
1022
//
1023
// This function creates an X.509 certificate from a signing request.  The
1024
// certificate is stored in the directory "path" or, if "path" is `NULL`, in a
1025
// per-user or system-wide (when running as root) certificate/key store.  The
1026
// generated certificate is signed by the named root certificate or, if
1027
// "root_name" is `NULL`, a site-wide default root certificate.  When
1028
// "root_name" is `NULL` and there is no site-wide default root certificate, a
1029
// self-signed certificate is generated instead.
1030
//
1031
// The "allowed_purpose" argument specifies the allowed purpose(s) used for the
1032
// credentials as a bitwise OR of the following constants:
1033
//
1034
// - `CUPS_CREDPURPOSE_SERVER_AUTH` for validating TLS servers,
1035
// - `CUPS_CREDPURPOSE_CLIENT_AUTH` for validating TLS clients,
1036
// - `CUPS_CREDPURPOSE_CODE_SIGNING` for validating compiled code,
1037
// - `CUPS_CREDPURPOSE_EMAIL_PROTECTION` for validating email messages,
1038
// - `CUPS_CREDPURPOSE_TIME_STAMPING` for signing timestamps to objects, and/or
1039
// - `CUPS_CREDPURPOSE_OCSP_SIGNING` for Online Certificate Status Protocol
1040
//   message signing.
1041
//
1042
// The "allowed_usage" argument specifies the allowed usage(s) for the
1043
// credentials as a bitwise OR of the following constants:
1044
//
1045
// - `CUPS_CREDUSAGE_DIGITAL_SIGNATURE`: digital signatures,
1046
// - `CUPS_CREDUSAGE_NON_REPUDIATION`: non-repudiation/content commitment,
1047
// - `CUPS_CREDUSAGE_KEY_ENCIPHERMENT`: key encipherment,
1048
// - `CUPS_CREDUSAGE_DATA_ENCIPHERMENT`: data encipherment,
1049
// - `CUPS_CREDUSAGE_KEY_AGREEMENT`: key agreement,
1050
// - `CUPS_CREDUSAGE_KEY_CERT_SIGN`: key certicate signing,
1051
// - `CUPS_CREDUSAGE_CRL_SIGN`: certificate revocation list signing,
1052
// - `CUPS_CREDUSAGE_ENCIPHER_ONLY`: encipherment only,
1053
// - `CUPS_CREDUSAGE_DECIPHER_ONLY`: decipherment only,
1054
// - `CUPS_CREDUSAGE_DEFAULT_CA`: defaults for CA certificates,
1055
// - `CUPS_CREDUSAGE_DEFAULT_TLS`: defaults for TLS certificates, and/or
1056
// - `CUPS_CREDUSAGE_ALL`: all usages.
1057
//
1058
// The "cb" and "cb_data" arguments specify a function and its data that are
1059
// used to validate any subjectAltName values in the signing request:
1060
//
1061
// ```
1062
// bool san_cb(const char *common_name, const char *alt_name, void *cb_data) {
1063
//   ... return true if OK and false if not ...
1064
// }
1065
// ```
1066
//
1067
// If `NULL`, a default validation function is used that allows "localhost" and
1068
// variations of the common name.
1069
//
1070
// The "expiration_date" argument specifies the expiration date and time as a
1071
// Unix `time_t` value in seconds.
1072
//
1073
1074
bool          // O - `true` on success, `false` on failure
1075
cupsSignCredentialsRequest(
1076
    const char         *path,   // I - Directory path for certificate/key store or `NULL` for default
1077
    const char         *common_name,  // I - Common name to use
1078
    const char         *request,  // I - PEM-encoded CSR
1079
    const char         *root_name,  // I - Root certificate
1080
    cups_credpurpose_t allowed_purpose, // I - Allowed credential purpose(s)
1081
    cups_credusage_t   allowed_usage, // I - Allowed credential usage(s)
1082
    cups_cert_san_cb_t cb,    // I - subjectAltName callback or `NULL` to allow just .local
1083
    void               *cb_data,  // I - Callback data
1084
    time_t             expiration_date) // I - Certificate expiration date
1085
0
{
1086
0
  bool    result = false;    // Return value
1087
0
  X509    *cert = NULL;   // Certificate
1088
0
  X509_REQ  *crq = NULL;   // Certificate request
1089
0
  X509    *root_cert = NULL; // Root certificate, if any
1090
0
  EVP_PKEY  *root_key = NULL; // Root private key, if any
1091
0
  char    defpath[1024],    // Default path
1092
0
    crtfile[1024],    // Certificate filename
1093
0
    root_crtfile[1024], // Root certificate filename
1094
0
    root_keyfile[1024]; // Root private key filename
1095
0
  time_t  curtime;    // Current time
1096
0
  ASN1_INTEGER  *serial;    // Serial number
1097
0
  ASN1_TIME *notBefore,   // Initial date
1098
0
    *notAfter;    // Expiration date
1099
0
  BIO   *bio;     // Input/output file
1100
0
  char    temp[1024];   // Temporary string
1101
0
  int   i, j,     // Looping vars
1102
0
    num_exts;   // Number of extensions
1103
0
  STACK_OF(X509_EXTENSION) *exts = NULL;// Extensions
1104
0
  X509_EXTENSION *ext;      // Current extension
1105
0
  cups_credpurpose_t purpose;   // Current purpose
1106
0
  cups_credusage_t usage;   // Current usage
1107
0
  bool    saw_usage = false,  // Saw NID_key_usage?
1108
0
    saw_ext_usage = false,  // Saw NID_ext_key_usage?
1109
0
    saw_san = false;  // Saw NID_subject_alt_name?
1110
1111
1112
0
  DEBUG_printf("cupsSignCredentialsRequest(path=\"%s\", common_name=\"%s\", request=\"%s\", root_name=\"%s\", allowed_purpose=0x%x, allowed_usage=0x%x, cb=%p, cb_data=%p, expiration_date=%ld)", path, common_name, request, root_name, allowed_purpose, allowed_usage, (void *)cb, cb_data, (long)expiration_date);
1113
1114
  // Filenames...
1115
0
  if (!path)
1116
0
    path = http_default_path(defpath, sizeof(defpath));
1117
1118
0
  if (!path || !common_name || !request)
1119
0
  {
1120
0
    _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(EINVAL), false);
1121
0
    return (false);
1122
0
  }
1123
1124
0
  if (!cb)
1125
0
    cb = http_default_san_cb;
1126
1127
  // Import the X.509 certificate request...
1128
0
  DEBUG_puts("1cupsCreateCredentials: Importing X.509 certificate request.");
1129
0
  if ((bio = BIO_new_mem_buf(request, (int)strlen(request))) != NULL)
1130
0
  {
1131
0
    PEM_read_bio_X509_REQ(bio, &crq, /*cb*/NULL, /*u*/NULL);
1132
0
    BIO_free(bio);
1133
0
  }
1134
1135
0
  if (!crq)
1136
0
  {
1137
0
    _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Unable to import X.509 certificate request."), 1);
1138
0
    return (false);
1139
0
  }
1140
1141
0
  if (X509_REQ_verify(crq, X509_REQ_get_pubkey(crq)) <= 0)
1142
0
  {
1143
0
    _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Unable to verify X.509 certificate request."), 1);
1144
0
    goto done;
1145
0
  }
1146
1147
  // Create the X.509 certificate...
1148
0
  DEBUG_puts("1cupsSignCredentialsRequest: Generating X.509 certificate.");
1149
1150
0
  if ((cert = X509_new()) == NULL)
1151
0
  {
1152
0
    _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Unable to create X.509 certificate."), 1);
1153
0
    goto done;
1154
0
  }
1155
1156
0
  curtime = time(NULL);
1157
1158
0
  notBefore = ASN1_TIME_new();
1159
0
  ASN1_TIME_set(notBefore, curtime);
1160
0
  X509_set_notBefore(cert, notBefore);
1161
0
  ASN1_TIME_free(notBefore);
1162
1163
0
  notAfter  = ASN1_TIME_new();
1164
0
  ASN1_TIME_set(notAfter, expiration_date);
1165
0
  X509_set_notAfter(cert, notAfter);
1166
0
  ASN1_TIME_free(notAfter);
1167
1168
0
  serial = ASN1_INTEGER_new();
1169
0
  ASN1_INTEGER_set(serial, (long)curtime);
1170
0
  X509_set_serialNumber(cert, serial);
1171
0
  ASN1_INTEGER_free(serial);
1172
1173
0
  X509_set_pubkey(cert, X509_REQ_get_pubkey(crq));
1174
1175
0
  X509_set_subject_name(cert, X509_REQ_get_subject_name(crq));
1176
0
  X509_set_version(cert, 2); // v3
1177
1178
  // Copy/verify extensions...
1179
0
  exts     = X509_REQ_get_extensions(crq);
1180
0
  num_exts = sk_X509_EXTENSION_num(exts);
1181
1182
0
  for (i = 0; i < num_exts; i ++)
1183
0
  {
1184
    // Get the extension object...
1185
0
    bool    add_ext = false;  // Add this extension?
1186
0
    ASN1_OBJECT   *obj;     // Extension object
1187
0
    ASN1_OCTET_STRING *extdata;   // Extension data string
1188
0
    unsigned char *data = NULL;   // Extension data bytes
1189
0
    int     datalen;    // Length of extension data
1190
1191
0
    ext     = sk_X509_EXTENSION_value(exts, i);
1192
0
    obj     = (ASN1_OBJECT *)X509_EXTENSION_get_object(ext);
1193
0
    extdata = (ASN1_OCTET_STRING *)X509_EXTENSION_get_data(ext);
1194
0
    datalen = i2d_ASN1_OCTET_STRING(extdata, &data);
1195
1196
#ifdef DEBUG
1197
    char *tempptr;        // Pointer into string
1198
1199
    for (j = 0, tempptr = temp; j < datalen; j ++, tempptr += 2)
1200
      snprintf(tempptr, sizeof(temp) - (size_t)(tempptr - temp), "%02X", data[j]);
1201
1202
    DEBUG_printf("1cupsSignCredentialsRequest: EXT%d=%s", OBJ_obj2nid(obj), temp);
1203
#endif // DEBUG
1204
1205
0
    switch (OBJ_obj2nid(obj))
1206
0
    {
1207
0
      case NID_ext_key_usage :
1208
0
          add_ext       = true;
1209
0
          saw_ext_usage = true;
1210
1211
0
          if (datalen < 12 || data[2] != 0x30 || data[3] != (datalen - 4))
1212
0
          {
1213
0
            _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Bad keyUsage extension in X.509 certificate request."), 1);
1214
0
      goto done;
1215
0
          }
1216
1217
0
          for (purpose = 0, j = 4; j < datalen; j += data[j + 1] + 2)
1218
0
          {
1219
0
            if ((j + 2) > datalen || (j + 2 + data[j + 1]) > datalen || data[j] != 0x06 || data[j + 1] != 8 || memcmp(data + j + 2, "+\006\001\005\005\007\003", 7))
1220
0
            {
1221
0
        _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Bad keyUsage extension in X.509 certificate request."), 1);
1222
0
        goto done;
1223
0
            }
1224
1225
0
            switch (data[j + 9])
1226
0
            {
1227
0
              case 1 :
1228
0
                  purpose |= CUPS_CREDPURPOSE_SERVER_AUTH;
1229
0
                  break;
1230
0
              case 2 :
1231
0
                  purpose |= CUPS_CREDPURPOSE_CLIENT_AUTH;
1232
0
                  break;
1233
0
              case 3 :
1234
0
                  purpose |= CUPS_CREDPURPOSE_CODE_SIGNING;
1235
0
                  break;
1236
0
              case 4 :
1237
0
                  purpose |= CUPS_CREDPURPOSE_EMAIL_PROTECTION;
1238
0
                  break;
1239
0
              case 8 :
1240
0
                  purpose |= CUPS_CREDPURPOSE_TIME_STAMPING;
1241
0
                  break;
1242
0
              case 9 :
1243
0
                  purpose |= CUPS_CREDPURPOSE_OCSP_SIGNING;
1244
0
                  break;
1245
0
        default :
1246
0
      _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Bad keyUsage extension in X.509 certificate request."), 1);
1247
0
      goto done;
1248
0
            }
1249
0
          }
1250
1251
0
          DEBUG_printf("1cupsSignCredentialsRequest: purpose=0x%04x", purpose);
1252
1253
0
          if (purpose & ~allowed_purpose)
1254
0
          {
1255
0
            _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Bad keyUsage extension in X.509 certificate request."), 1);
1256
0
      goto done;
1257
0
          }
1258
0
          break;
1259
1260
0
      case NID_key_usage :
1261
0
          add_ext   = true;
1262
0
          saw_usage = true;
1263
1264
0
          if (datalen < 6 || datalen > 7 || data[2] != 0x03 || data[3] != (datalen - 4))
1265
0
          {
1266
0
            _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Bad extKeyUsage extension in X.509 certificate request."), 1);
1267
0
      goto done;
1268
0
          }
1269
1270
0
          usage = 0;
1271
0
          if (data[5] & 0x80)
1272
0
      usage |= CUPS_CREDUSAGE_DIGITAL_SIGNATURE;
1273
0
          if (data[5] & 0x40)
1274
0
      usage |= CUPS_CREDUSAGE_NON_REPUDIATION;
1275
0
          if (data[5] & 0x20)
1276
0
      usage |= CUPS_CREDUSAGE_KEY_ENCIPHERMENT;
1277
0
          if (data[5] & 0x10)
1278
0
      usage |= CUPS_CREDUSAGE_DATA_ENCIPHERMENT;
1279
0
          if (data[5] & 0x08)
1280
0
      usage |= CUPS_CREDUSAGE_KEY_AGREEMENT;
1281
0
          if (data[5] & 0x04)
1282
0
      usage |= CUPS_CREDUSAGE_KEY_CERT_SIGN;
1283
0
          if (data[5] & 0x02)
1284
0
      usage |= CUPS_CREDUSAGE_CRL_SIGN;
1285
0
          if (data[5] & 0x01)
1286
0
      usage |= CUPS_CREDUSAGE_ENCIPHER_ONLY;
1287
0
          if (datalen == 7 && (data[6] & 0x80))
1288
0
      usage |= CUPS_CREDUSAGE_DECIPHER_ONLY;
1289
1290
0
          DEBUG_printf("1cupsSignCredentialsRequest: usage=0x%04x", usage);
1291
1292
0
          if (usage & ~allowed_usage)
1293
0
          {
1294
0
            _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Bad extKeyUsage extension in X.509 certificate request."), 1);
1295
0
      goto done;
1296
0
          }
1297
0
          break;
1298
1299
0
      case NID_subject_alt_name :
1300
0
          add_ext = true;
1301
0
          saw_san = true;
1302
1303
0
          if (datalen < 4 || data[2] != 0x30 || data[3] != (datalen - 4))
1304
0
          {
1305
0
            _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Bad subjectAltName extension in X.509 certificate request."), 1);
1306
0
      goto done;
1307
0
          }
1308
1309
          // Parse the SAN values (there should be an easier/standard OpenSSL API to do this!)
1310
0
          for (j = 4; j < datalen; j += data[j + 1] + 2)
1311
0
          {
1312
      // Stop if the element header or value runs past the extension data...
1313
0
      if ((j + 2) > datalen || (j + 2 + data[j + 1]) > datalen)
1314
0
        break;
1315
1316
0
            if (data[j] == 0x82 && data[j + 1])
1317
0
            {
1318
              // GENERAL_STRING for DNS
1319
0
              memcpy(temp, data + j + 2, data[j + 1]);
1320
0
              temp[data[j + 1]] = '\0';
1321
1322
0
              DEBUG_printf("1cupsSignCredentialsRequest: SAN %s", temp);
1323
1324
0
              if (!(cb)(common_name, temp, cb_data))
1325
0
              {
1326
0
                _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Validation of subjectAltName in X.509 certificate request failed."), 1);
1327
0
                goto done;
1328
0
              }
1329
0
      }
1330
0
          }
1331
0
          break;
1332
0
    }
1333
1334
0
    OPENSSL_free(data);
1335
1336
    // If we get this far, the object is OK and we can add it...
1337
0
    if (add_ext && !X509_add_ext(cert, ext, -1))
1338
0
      goto done;
1339
0
  }
1340
1341
  // Add basic constraints for an "edge" certificate...
1342
0
  if ((ext = X509V3_EXT_conf_nid(/*conf*/NULL, /*ctx*/NULL, NID_basic_constraints, "critical,CA:FALSE,pathlen:0")) == NULL || !X509_add_ext(cert, ext, -1))
1343
0
  {
1344
0
    _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Unable to add extension to X.509 certificate."), 1);
1345
0
    goto done;
1346
0
  }
1347
1348
  // Add key usage extensions as needed...
1349
0
  if (!saw_usage)
1350
0
  {
1351
0
    if ((ext = X509V3_EXT_conf_nid(/*conf*/NULL, /*ctx*/NULL, NID_key_usage, "critical,digitalSignature,keyEncipherment")) == NULL || !X509_add_ext(cert, ext, -1))
1352
0
    {
1353
0
      _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Unable to add extension to X.509 certificate."), 1);
1354
0
      goto done;
1355
0
    }
1356
0
  }
1357
1358
0
  if (!saw_ext_usage)
1359
0
  {
1360
0
    if ((ext = X509V3_EXT_conf_nid(/*conf*/NULL, /*ctx*/NULL, NID_ext_key_usage, tls_usage_strings[0])) == NULL || !X509_add_ext(cert, ext, -1))
1361
0
    {
1362
0
      _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Unable to add extension to X.509 certificate."), 1);
1363
0
      goto done;
1364
0
    }
1365
0
  }
1366
1367
0
  if (!saw_san)
1368
0
  {
1369
0
    if ((ext = openssl_create_san(common_name, /*num_alt_names*/0, /*alt_names*/NULL)) == NULL || !X509_add_ext(cert, ext, -1))
1370
0
    {
1371
0
      _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Unable to add extension to X.509 certificate."), 1);
1372
0
      goto done;
1373
0
    }
1374
0
  }
1375
1376
  // Try loading a root certificate...
1377
0
  http_make_path(root_crtfile, sizeof(root_crtfile), path, root_name ? root_name : "_site_", "crt");
1378
0
  http_make_path(root_keyfile, sizeof(root_keyfile), path, root_name ? root_name : "_site_", "key");
1379
1380
0
  if (!access(root_crtfile, 0) && !access(root_keyfile, 0))
1381
0
  {
1382
0
    if ((bio = BIO_new_file(root_crtfile, "rb")) != NULL)
1383
0
    {
1384
0
      PEM_read_bio_X509(bio, &root_cert, /*cb*/NULL, /*u*/NULL);
1385
0
      BIO_free(bio);
1386
1387
0
      if ((bio = BIO_new_file(root_keyfile, "rb")) != NULL)
1388
0
      {
1389
0
  PEM_read_bio_PrivateKey(bio, &root_key, /*cb*/NULL, /*u*/NULL);
1390
0
  BIO_free(bio);
1391
0
      }
1392
1393
0
      if (!root_key)
1394
0
      {
1395
        // Only use root certificate if we have the key...
1396
0
        X509_free(root_cert);
1397
0
        root_cert = NULL;
1398
0
      }
1399
0
    }
1400
0
  }
1401
1402
0
  if (!root_cert || !root_key)
1403
0
  {
1404
0
    _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Unable to load X.509 CA certificate and private key."), 1);
1405
0
    goto done;
1406
0
  }
1407
1408
0
  X509_set_issuer_name(cert, X509_get_subject_name(root_cert));
1409
0
  X509_sign(cert, root_key, EVP_sha256());
1410
1411
  // Save the certificate...
1412
0
  http_make_path(crtfile, sizeof(crtfile), path, common_name, "crt");
1413
1414
0
  if ((bio = BIO_new_file(crtfile, "wb")) == NULL)
1415
0
  {
1416
0
    _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(errno), 0);
1417
0
    goto done;
1418
0
  }
1419
1420
0
  if (!PEM_write_bio_X509(bio, cert))
1421
0
  {
1422
0
    _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Unable to write X.509 certificate."), 1);
1423
0
    BIO_free(bio);
1424
0
    goto done;
1425
0
  }
1426
1427
0
  PEM_write_bio_X509(bio, root_cert);
1428
1429
0
  BIO_free(bio);
1430
0
  result = true;
1431
0
  DEBUG_puts("1cupsSignRequest: Successfully created credentials.");
1432
1433
  // Cleanup...
1434
0
  done:
1435
1436
0
  if (exts)
1437
0
    sk_X509_EXTENSION_pop_free(exts, X509_EXTENSION_free);
1438
0
  if (crq)
1439
0
    X509_REQ_free(crq);
1440
0
  if (cert)
1441
0
    X509_free(cert);
1442
0
  if (root_cert)
1443
0
    X509_free(root_cert);
1444
0
  if (root_key)
1445
0
    EVP_PKEY_free(root_key);
1446
1447
0
  return (result);
1448
0
}
1449
1450
1451
//
1452
// 'httpCopyPeerCredentials()' - Copy the credentials associated with the peer in an encrypted connection.
1453
//
1454
1455
char *          // O - PEM-encoded X.509 certificate chain or `NULL`
1456
httpCopyPeerCredentials(http_t *http) // I - Connection to server
1457
0
{
1458
0
  char    *credentials = NULL; // Return value
1459
0
  size_t  alloc_creds = 0;  // Allocated size
1460
0
  STACK_OF(X509) *chain;    // Certificate chain
1461
1462
1463
0
  DEBUG_printf("httpCopyPeerCredentials(http=%p)", (void *)http);
1464
1465
0
  if (http && http->tls)
1466
0
  {
1467
    // Get the chain of certificates for the remote end...
1468
0
    chain = SSL_get_peer_cert_chain(http->tls);
1469
1470
0
    DEBUG_printf("1httpCopyPeerCredentials: chain=%p", (void *)chain);
1471
1472
0
    if (chain)
1473
0
    {
1474
      // Loop through the certificates, adding them to the string...
1475
0
      int i,      // Looping var
1476
0
    count;      // Number of certs
1477
1478
0
      for (i = 0, count = sk_X509_num(chain); i < count; i ++)
1479
0
      {
1480
0
  X509  *cert = sk_X509_value(chain, i);
1481
            // Current certificate
1482
0
  BIO *bio = BIO_new(BIO_s_mem());
1483
            // Memory buffer for cert
1484
1485
0
        DEBUG_printf("1httpCopyPeerCredentials: chain[%d/%d]=%p", i + 1, count, (void *)cert);
1486
1487
#ifdef DEBUG
1488
  char subjectName[256], issuerName[256];
1489
1490
  if (X509_NAME_get_text_by_NID(X509_get_subject_name(cert), NID_commonName, subjectName, sizeof(subjectName)) < 0)
1491
    cupsCopyString(subjectName, "unknown", sizeof(subjectName));
1492
1493
  if (X509_NAME_get_text_by_NID(X509_get_issuer_name(cert), NID_commonName, issuerName, sizeof(issuerName)) < 0)
1494
    cupsCopyString(issuerName, "unknown", sizeof(issuerName));
1495
1496
  DEBUG_printf("1httpCopyPeerCredentials: subjectName=\"%s\", issuerName=\"%s\"", subjectName, issuerName);
1497
1498
  STACK_OF(GENERAL_NAME) *names;  // subjectAltName values
1499
  names = X509_get_ext_d2i(cert, NID_subject_alt_name, /*crit*/NULL, /*idx*/NULL);
1500
  DEBUG_printf("1httpCopyPeerCredentials: subjectAltNames=%p(%d)", (void *)names, names ? sk_GENERAL_NAME_num(names) : 0);
1501
        if (names)
1502
          GENERAL_NAMES_free(names);
1503
#endif // DEBUG
1504
1505
0
  if (bio)
1506
0
  {
1507
0
    long  bytes;      // Number of bytes
1508
0
    char  *buffer;    // Pointer to bytes
1509
1510
0
    if (PEM_write_bio_X509(bio, cert))
1511
0
    {
1512
0
      if ((bytes = BIO_get_mem_data(bio, &buffer)) > 0)
1513
0
      {
1514
        // Expand credentials string...
1515
0
        if ((credentials = realloc(credentials, alloc_creds + (size_t)bytes + 1)) != NULL)
1516
0
        {
1517
          // Copy PEM-encoded data...
1518
0
          memcpy(credentials + alloc_creds, buffer, bytes);
1519
0
          credentials[alloc_creds + (size_t)bytes] = '\0';
1520
0
          alloc_creds += (size_t)bytes;
1521
0
        }
1522
0
      }
1523
0
    }
1524
1525
0
    BIO_free(bio);
1526
1527
0
    if (!credentials)
1528
0
      break;
1529
0
  }
1530
0
      }
1531
0
    }
1532
0
  }
1533
1534
0
  DEBUG_printf("1httpCopyPeerCredentials: Returning \"%s\".", credentials);
1535
1536
0
  return (credentials);
1537
0
}
1538
1539
1540
//
1541
// '_httpCreateCredentials()' - Create credentials in the internal format.
1542
//
1543
1544
_http_tls_credentials_t *   // O - Internal credentials
1545
_httpCreateCredentials(
1546
    const char *credentials,    // I - Credentials string
1547
    const char *key)      // I - Private key string
1548
0
{
1549
0
  _http_tls_credentials_t *hcreds;  // Credentials
1550
1551
1552
0
  DEBUG_printf("_httpCreateCredentials(credentials=\"%s\", key=\"%s\")", credentials, key);
1553
1554
0
  if (!credentials || !*credentials || !key || !*key)
1555
0
    return (NULL);
1556
1557
0
  if ((hcreds = calloc(1, sizeof(_http_tls_credentials_t))) == NULL)
1558
0
    return (NULL);
1559
1560
0
  hcreds->use = 1;
1561
1562
  // Load the certificates...
1563
0
  if ((hcreds->certs = openssl_load_x509(credentials)) == NULL)
1564
0
  {
1565
0
    _httpFreeCredentials(hcreds);
1566
0
    hcreds = NULL;
1567
0
  }
1568
0
  else
1569
0
  {
1570
    // Load the private key...
1571
0
    BIO *bio;       // Basic I/O for string
1572
1573
0
    if ((bio = BIO_new_mem_buf(key, strlen(key))) == NULL)
1574
0
    {
1575
0
      _httpFreeCredentials(hcreds);
1576
0
      hcreds = NULL;
1577
0
    }
1578
1579
0
    if (!PEM_read_bio_PrivateKey(bio, &hcreds->key, NULL, NULL))
1580
0
    {
1581
0
      _httpFreeCredentials(hcreds);
1582
0
      hcreds = NULL;
1583
0
    }
1584
0
  }
1585
1586
0
  DEBUG_printf("1_httpCreateCredentials: Returning %p.", (void *)hcreds);
1587
1588
0
  return (hcreds);
1589
0
}
1590
1591
1592
//
1593
// '_httpFreeCredentials()' - Free internal credentials.
1594
//
1595
1596
void
1597
_httpFreeCredentials(
1598
    _http_tls_credentials_t *hcreds)  // I - Internal credentials
1599
0
{
1600
0
  if (!hcreds)
1601
0
    return;
1602
1603
0
  if (hcreds->use)
1604
0
    hcreds->use --;
1605
1606
0
  if (hcreds->use)
1607
0
    return;
1608
1609
0
  sk_X509_free(hcreds->certs);
1610
0
  free(hcreds);
1611
0
}
1612
1613
1614
//
1615
// 'httpGetSecurity()' - Get the TLS version and cipher suite used by a connection.
1616
//
1617
// This function gets the TLS version and cipher suite being used by a
1618
// connection, if any.  The string is copied to "buffer" and is of the form
1619
// "TLS/major.minor CipherSuite".  If not encrypted, the buffer is cleared to
1620
// the empty string.
1621
//
1622
// @since CUPS 2.5@
1623
//
1624
1625
const char *        // O - Security information or `NULL` if not encrypted
1626
httpGetSecurity(http_t *http,   // I - HTTP connection
1627
                char   *buffer,   // I - String buffer
1628
                size_t bufsize)   // I - Size of buffer
1629
0
{
1630
0
  const char  *cipherName;    // Cipher suite name
1631
1632
1633
  // Range check input...
1634
0
  if (buffer)
1635
0
    *buffer = '\0';
1636
1637
0
  if (!http || !http->tls || !buffer || bufsize < 16)
1638
0
    return (NULL);
1639
1640
  // Record the TLS version and cipher suite...
1641
0
  cipherName = SSL_get_cipher_name(http->tls);
1642
1643
0
  switch (SSL_version(http->tls))
1644
0
  {
1645
0
    default :
1646
0
        snprintf(buffer, bufsize, "TLS/?.? %s", cipherName);
1647
0
        break;
1648
1649
0
    case TLS1_VERSION :
1650
0
        snprintf(buffer, bufsize, "TLS/1.0 %s", cipherName);
1651
0
        break;
1652
1653
0
    case TLS1_1_VERSION :
1654
0
        snprintf(buffer, bufsize, "TLS/1.1 %s", cipherName);
1655
0
        break;
1656
1657
0
    case TLS1_2_VERSION :
1658
0
        snprintf(buffer, bufsize, "TLS/1.2 %s", cipherName);
1659
0
        break;
1660
1661
0
#  ifdef TLS1_3_VERSION
1662
0
    case TLS1_3_VERSION :
1663
0
        snprintf(buffer, bufsize, "TLS/1.3 %s", cipherName);
1664
0
        break;
1665
0
#  endif // TLS1_3_VERSION
1666
0
  }
1667
1668
0
  return (buffer);
1669
0
}
1670
1671
1672
//
1673
// '_httpTLSInitialize()' - Initialize the TLS stack.
1674
//
1675
1676
void
1677
_httpTLSInitialize(void)
1678
0
{
1679
  // OpenSSL no longer requires explicit initialization...
1680
0
}
1681
1682
1683
//
1684
// '_httpTLSPending()' - Return the number of pending TLS-encrypted bytes.
1685
//
1686
1687
size_t          // O - Bytes available
1688
_httpTLSPending(http_t *http)   // I - HTTP connection
1689
0
{
1690
0
  return ((size_t)SSL_pending(http->tls));
1691
0
}
1692
1693
1694
//
1695
// '_httpTLSRead()' - Read from a SSL/TLS connection.
1696
//
1697
1698
int         // O - Bytes read
1699
_httpTLSRead(http_t *http,    // I - Connection to server
1700
       char   *buf,   // I - Buffer to store data
1701
       int    len)    // I - Length of buffer
1702
0
{
1703
0
  int bytes = SSL_read((SSL *)(http->tls), buf, len);
1704
          // Bytes read
1705
1706
0
  DEBUG_printf("7_httpTLSRead(http=%p, buf=%p, len=%d) returning %d", (void *)http, (void *)buf, len, bytes);
1707
1708
0
  if (bytes > 0)
1709
0
    return (bytes);
1710
1711
  // For now, make difference only for error after which we can retry, EPIPE otherwise...
1712
0
  if (SSL_get_error(http->tls, bytes) == SSL_ERROR_WANT_READ)
1713
0
    errno = EAGAIN;
1714
0
  else
1715
0
    errno = EPIPE;
1716
1717
0
  return (-1);
1718
0
}
1719
1720
1721
//
1722
// '_httpTLSStart()' - Set up SSL/TLS support on a connection.
1723
//
1724
1725
bool          // O - `true` on success, `false` on failure
1726
_httpTLSStart(http_t *http)   // I - Connection to server
1727
0
{
1728
0
  const char  *keypath;   // Certificate store path
1729
0
  BIO   *bio;     // Basic input/output context
1730
0
  SSL_CTX *context;   // Encryption context
1731
0
  char    hostname[256],    // Hostname
1732
0
    cipherlist[256];  // List of cipher suites
1733
0
  unsigned long error;      // Error code, if any
1734
0
  _cups_globals_t *cg = _cupsGlobals(); // Per-thread globals
1735
0
  static const uint16_t versions[] =  // SSL/TLS versions
1736
0
  {
1737
0
    TLS1_VERSION,     // No more SSL support in OpenSSL
1738
0
    TLS1_VERSION,     // TLS/1.0
1739
0
    TLS1_1_VERSION,     // TLS/1.1
1740
0
    TLS1_2_VERSION,     // TLS/1.2
1741
0
#ifdef TLS1_3_VERSION
1742
0
    TLS1_3_VERSION,     // TLS/1.3
1743
    TLS1_3_VERSION      // TLS/1.3 (max)
1744
#else
1745
    TLS1_2_VERSION,     // TLS/1.2
1746
    TLS1_2_VERSION      // TLS/1.2 (max)
1747
#endif // TLS1_3_VERSION
1748
0
  };
1749
1750
1751
0
  DEBUG_printf("3_httpTLSStart(http=%p)", (void *)http);
1752
1753
0
  if (!cg->client_conf_loaded)
1754
0
  {
1755
0
    DEBUG_puts("4_httpTLSStart: Setting defaults.");
1756
0
    _cupsSetDefaults();
1757
0
    DEBUG_printf("4_httpTLSStart: tls_options=%x", tls_options);
1758
0
  }
1759
1760
0
  cupsMutexLock(&tls_mutex);
1761
0
  keypath = tls_keypath;
1762
0
  cupsMutexUnlock(&tls_mutex);
1763
1764
0
  if (http->mode == _HTTP_MODE_SERVER && !keypath)
1765
0
  {
1766
0
    DEBUG_puts("4_httpTLSStart: cupsSetServerCredentials not called.");
1767
0
    http->error  = errno = EINVAL;
1768
0
    http->status = HTTP_STATUS_ERROR;
1769
0
    _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Server credentials not set."), 1);
1770
1771
0
    return (false);
1772
0
  }
1773
1774
0
  if (http->mode == _HTTP_MODE_CLIENT)
1775
0
  {
1776
    // Negotiate a TLS connection as a client...
1777
0
    context = SSL_CTX_new(TLS_client_method());
1778
0
    if (http->tls_credentials)
1779
0
    {
1780
0
      int i,      // Looping var
1781
0
    count;      // Number of certificates
1782
1783
0
      DEBUG_puts("4_httpTLSStart: Using client certificate.");
1784
0
      SSL_CTX_use_certificate(context, sk_X509_value(http->tls_credentials->certs, 0));
1785
0
      SSL_CTX_use_PrivateKey(context, http->tls_credentials->key);
1786
1787
0
      count = sk_X509_num(http->tls_credentials->certs);
1788
0
      for (i = 1; i < count; i ++)
1789
0
        SSL_CTX_add_extra_chain_cert(context, sk_X509_value(http->tls_credentials->certs, i));
1790
0
    }
1791
0
  }
1792
0
  else
1793
0
  {
1794
    // Negotiate a TLS connection as a server
1795
0
    char  crtfile[1024],    // Certificate file
1796
0
    keyfile[1024];    // Private key file
1797
0
    const char  *cn = NULL,   // Common name to lookup
1798
0
    *cnptr;     // Pointer into common name
1799
0
    bool  have_creds = false;  // Have credentials?
1800
1801
0
    context = SSL_CTX_new(TLS_server_method());
1802
1803
    // Find the TLS certificate...
1804
0
    cupsMutexLock(&tls_mutex);
1805
1806
0
    if (!tls_common_name)
1807
0
    {
1808
0
      cupsMutexUnlock(&tls_mutex);
1809
1810
0
      if (http->fields[HTTP_FIELD_HOST])
1811
0
      {
1812
  // Use hostname for TLS upgrade...
1813
0
  cupsCopyString(hostname, http->fields[HTTP_FIELD_HOST], sizeof(hostname));
1814
0
      }
1815
0
      else
1816
0
      {
1817
  // Resolve hostname from connection address...
1818
0
  http_addr_t addr;   // Connection address
1819
0
  socklen_t addrlen;  // Length of address
1820
1821
0
  addrlen = sizeof(addr);
1822
0
  if (getsockname(http->fd, (struct sockaddr *)&addr, &addrlen))
1823
0
  {
1824
    // Unable to get local socket address so use default...
1825
0
    DEBUG_printf("4_httpTLSStart: Unable to get socket address: %s", strerror(errno));
1826
0
    hostname[0] = '\0';
1827
0
  }
1828
0
  else if (httpAddrIsLocalhost(&addr))
1829
0
  {
1830
    // Local access top use default...
1831
0
    hostname[0] = '\0';
1832
0
  }
1833
0
  else
1834
0
  {
1835
    // Lookup the socket address...
1836
0
    httpAddrLookup(&addr, hostname, sizeof(hostname));
1837
0
    DEBUG_printf("4_httpTLSStart: Resolved socket address to \"%s\".", hostname);
1838
0
  }
1839
0
      }
1840
1841
0
      if (_cups_isdigit(hostname[0]) || hostname[0] == '[')
1842
0
  hostname[0] = '\0';   // Don't allow numeric addresses
1843
1844
0
      if (hostname[0])
1845
0
  cn = hostname;
1846
1847
0
      cupsMutexLock(&tls_mutex);
1848
0
    }
1849
1850
0
    if (!cn)
1851
0
      cn = tls_common_name;
1852
1853
0
    DEBUG_printf("4_httpTLSStart: Using common name \"%s\"...", cn);
1854
1855
0
    if (cn)
1856
0
    {
1857
      // First look in the CUPS keystore...
1858
0
      http_make_path(crtfile, sizeof(crtfile), tls_keypath, cn, "crt");
1859
0
      http_make_path(keyfile, sizeof(keyfile), tls_keypath, cn, "key");
1860
1861
0
      if (access(crtfile, R_OK) || access(keyfile, R_OK))
1862
0
      {
1863
        // No CUPS-managed certs, look for CA certs...
1864
0
        char cacrtfile[1024], cakeyfile[1024];  // CA cert files
1865
1866
0
        snprintf(cacrtfile, sizeof(cacrtfile), "/etc/letsencrypt/live/%s/fullchain.pem", cn);
1867
0
        snprintf(cakeyfile, sizeof(cakeyfile), "/etc/letsencrypt/live/%s/privkey.pem", cn);
1868
1869
0
        if ((access(cacrtfile, R_OK) || access(cakeyfile, R_OK)) && (cnptr = strchr(cn, '.')) != NULL)
1870
0
        {
1871
          // Try just domain name...
1872
0
          cnptr ++;
1873
0
          if (strchr(cnptr, '.'))
1874
0
          {
1875
0
            snprintf(cacrtfile, sizeof(cacrtfile), "/etc/letsencrypt/live/%s/fullchain.pem", cnptr);
1876
0
            snprintf(cakeyfile, sizeof(cakeyfile), "/etc/letsencrypt/live/%s/privkey.pem", cnptr);
1877
0
          }
1878
0
        }
1879
1880
0
        if (!access(cacrtfile, R_OK) && !access(cakeyfile, R_OK))
1881
0
        {
1882
          // Use the CA certs...
1883
0
          cupsCopyString(crtfile, cacrtfile, sizeof(crtfile));
1884
0
          cupsCopyString(keyfile, cakeyfile, sizeof(keyfile));
1885
1886
0
          have_creds = true;
1887
0
        }
1888
0
      }
1889
0
      else
1890
0
      {
1891
        // CUPS-managed self-signed certs: use them only if they have
1892
        // not expired, otherwise let the auto-create code path below
1893
        // regenerate them (Issue #1519). cupsGetCredentialsExpiration()
1894
        // expects a PEM string, not a file path, so load the cert via
1895
        // cupsCopyCredentials() first.
1896
0
        char  *creds = cupsCopyCredentials(tls_keypath, cn);
1897
          // PEM-encoded certificate
1898
1899
0
        have_creds = cupsGetCredentialsExpiration(creds) > time(NULL);
1900
0
        free(creds);
1901
0
      }
1902
0
    }
1903
1904
0
    if (!have_creds && tls_auto_create && cn)
1905
0
    {
1906
0
      DEBUG_printf("4_httpTLSStart: Auto-create credentials for \"%s\".", cn);
1907
1908
0
      if (!cupsCreateCredentials(tls_keypath, false, CUPS_CREDPURPOSE_SERVER_AUTH, CUPS_CREDTYPE_DEFAULT, CUPS_CREDUSAGE_DEFAULT_TLS, NULL, NULL, NULL, NULL, NULL, cn, NULL, 0, NULL, NULL, time(NULL) + 3650 * 86400))
1909
0
      {
1910
0
  DEBUG_printf("4_httpTLSStart: cupsCreateCredentials failed: %s", cupsGetErrorString());
1911
0
  http->error  = errno = EINVAL;
1912
0
  http->status = HTTP_STATUS_ERROR;
1913
0
  SSL_CTX_free(context);
1914
0
        cupsMutexUnlock(&tls_mutex);
1915
1916
0
  return (false);
1917
0
      }
1918
0
    }
1919
1920
0
    cupsMutexUnlock(&tls_mutex);
1921
1922
0
    DEBUG_printf("4_httpTLSStart: Using private key file '%s'.", keyfile);
1923
0
    DEBUG_printf("4_httpTLSStart: Using certificate file '%s'.", crtfile);
1924
1925
0
    if (!SSL_CTX_use_PrivateKey_file(context, keyfile, SSL_FILETYPE_PEM) || !SSL_CTX_use_certificate_chain_file(context, crtfile))
1926
0
    {
1927
      // Unable to load private key or certificate...
1928
0
      DEBUG_puts("4_httpTLSStart: Unable to use private key or certificate chain file.");
1929
0
      if ((error = ERR_get_error()) != 0)
1930
0
        _cupsSetError(IPP_STATUS_ERROR_CUPS_PKI, ERR_error_string(error, NULL), 0);
1931
1932
0
      http->status = HTTP_STATUS_ERROR;
1933
0
      http->error  = EIO;
1934
1935
0
      SSL_CTX_free(context);
1936
1937
0
      return (false);
1938
0
    }
1939
0
  }
1940
1941
  // Set TLS options...
1942
0
  cupsCopyString(cipherlist, "HIGH:!DH:+DHE", sizeof(cipherlist));
1943
0
  if ((tls_options & _HTTP_TLS_ALLOW_RC4) && http->mode == _HTTP_MODE_CLIENT)
1944
0
    cupsConcatString(cipherlist, ":+RC4", sizeof(cipherlist));
1945
0
  else
1946
0
    cupsConcatString(cipherlist, ":!RC4", sizeof(cipherlist));
1947
0
  if (tls_options & _HTTP_TLS_DENY_CBC)
1948
0
    cupsConcatString(cipherlist, ":!SHA1:!SHA256:!SHA384", sizeof(cipherlist));
1949
0
  cupsConcatString(cipherlist, ":@STRENGTH", sizeof(cipherlist));
1950
1951
0
  DEBUG_printf("4_httpTLSStart: cipherlist='%s', tls_min_version=%d, tls_max_version=%d", cipherlist, tls_min_version, tls_max_version);
1952
1953
0
  SSL_CTX_set_min_proto_version(context, versions[tls_min_version]);
1954
0
  SSL_CTX_set_max_proto_version(context, versions[tls_max_version]);
1955
0
  SSL_CTX_set_cipher_list(context, cipherlist);
1956
1957
  // Setup a TLS session
1958
0
  cupsMutexLock(&tls_mutex);
1959
0
  if (!tls_bio_method)
1960
0
  {
1961
0
    tls_bio_method = BIO_meth_new(BIO_get_new_index(), "http");
1962
0
    BIO_meth_set_ctrl(tls_bio_method, http_bio_ctrl);
1963
0
    BIO_meth_set_create(tls_bio_method, http_bio_new);
1964
0
    BIO_meth_set_destroy(tls_bio_method, http_bio_free);
1965
0
    BIO_meth_set_read(tls_bio_method, http_bio_read);
1966
0
    BIO_meth_set_puts(tls_bio_method, http_bio_puts);
1967
0
    BIO_meth_set_write(tls_bio_method, http_bio_write);
1968
0
  }
1969
1970
0
  bio = BIO_new(tls_bio_method);
1971
0
  cupsMutexUnlock(&tls_mutex);
1972
1973
0
  BIO_ctrl(bio, BIO_C_SET_FILE_PTR, 0, (char *)http);
1974
1975
0
  http->tls = SSL_new(context);
1976
0
  SSL_set_bio(http->tls, bio, bio);
1977
1978
0
  if (http->mode == _HTTP_MODE_CLIENT)
1979
0
  {
1980
    // Negotiate as a client...
1981
0
    DEBUG_printf("4_httpTLSStart: Setting server name TLS extension to '%s'...", http->hostname);
1982
0
    SSL_set_tlsext_host_name(http->tls, http->hostname);
1983
1984
0
    DEBUG_puts("4_httpTLSStart: Calling SSL_connect...");
1985
0
    if (SSL_connect(http->tls) < 1)
1986
0
    {
1987
      // Failed
1988
0
      if ((error = ERR_get_error()) != 0)
1989
0
        _cupsSetError(IPP_STATUS_ERROR_CUPS_PKI, ERR_error_string(error, NULL), 0);
1990
1991
0
      http->status = HTTP_STATUS_ERROR;
1992
0
      http->error  = EPIPE;
1993
1994
0
      SSL_CTX_free(context);
1995
1996
0
      SSL_free(http->tls);
1997
0
      http->tls = NULL;
1998
1999
0
      DEBUG_printf("4_httpTLSStart: Returning false (%s)", ERR_error_string(error, NULL));
2000
2001
0
      return (false);
2002
0
    }
2003
0
  }
2004
0
  else
2005
0
  {
2006
    // Negotiate as a server...
2007
0
    DEBUG_puts("4_httpTLSStart: Calling SSL_accept...");
2008
0
    if (SSL_accept(http->tls) < 1)
2009
0
    {
2010
      // Failed
2011
0
      if ((error = ERR_get_error()) != 0)
2012
0
        _cupsSetError(IPP_STATUS_ERROR_CUPS_PKI, ERR_error_string(error, NULL), 0);
2013
2014
0
      http->status = HTTP_STATUS_ERROR;
2015
0
      http->error  = EPIPE;
2016
2017
0
      SSL_CTX_free(context);
2018
2019
0
      SSL_free(http->tls);
2020
0
      http->tls = NULL;
2021
2022
0
      DEBUG_printf("4_httpTLSStart: Returning false (%s)", ERR_error_string(error, NULL));
2023
2024
0
      return (false);
2025
0
    }
2026
0
  }
2027
2028
0
  DEBUG_puts("4_httpTLSStart: Returning true.");
2029
2030
0
  return (true);
2031
0
}
2032
2033
2034
//
2035
// '_httpTLSStop()' - Shut down SSL/TLS on a connection.
2036
//
2037
2038
void
2039
_httpTLSStop(http_t *http)    // I - Connection to server
2040
0
{
2041
0
  SSL_CTX *context;   // Context for encryption
2042
2043
2044
0
  context = SSL_get_SSL_CTX(http->tls);
2045
2046
0
  SSL_shutdown(http->tls);
2047
0
  SSL_CTX_free(context);
2048
0
  SSL_free(http->tls);
2049
2050
0
  http->tls = NULL;
2051
0
}
2052
2053
2054
//
2055
// '_httpTLSWrite()' - Write to a SSL/TLS connection.
2056
//
2057
2058
int         // O - Bytes written
2059
_httpTLSWrite(http_t     *http,   // I - Connection to server
2060
        const char *buf,    // I - Buffer holding data
2061
        int        len)   // I - Length of buffer
2062
0
{
2063
0
  int bytes = SSL_write(http->tls, buf, len);
2064
          // Bytes written
2065
2066
0
  DEBUG_printf("7_httpTLSWrite(http=%p, buf=%p, len=%d) got %d", (void *)http, (void *)buf, len, bytes);
2067
2068
0
  if (bytes > 0)
2069
0
    return (bytes);
2070
2071
  // For now, make difference only for error after which we can retry, EPIPE otherwise...
2072
0
  if (SSL_get_error(http->tls, bytes) == SSL_ERROR_WANT_WRITE)
2073
0
    errno = EAGAIN;
2074
0
  else
2075
0
    errno = EPIPE;
2076
2077
0
  return (-1);
2078
0
}
2079
2080
2081
//
2082
// '_httpUseCredentials()' - Increment the use count for internal credentials.
2083
//
2084
2085
_http_tls_credentials_t *   // O - Internal credentials
2086
_httpUseCredentials(
2087
    _http_tls_credentials_t *hcreds)  // I - Internal credentials
2088
0
{
2089
0
  if (hcreds)
2090
0
    hcreds->use ++;
2091
2092
0
  return (hcreds);
2093
0
}
2094
2095
2096
//
2097
// 'http_bio_ctrl()' - Control the HTTP connection.
2098
//
2099
2100
static long       // O - Result/data
2101
http_bio_ctrl(BIO  *h,      // I - BIO data
2102
              int  cmd,     // I - Control command
2103
        long arg1,    // I - First argument
2104
        void *arg2)   // I - Second argument
2105
0
{
2106
0
  DEBUG_printf("8http_bio_ctl(h=%p, cmd=%d, arg1=%ld, arg2=%p)", (void *)h, cmd, arg1, arg2);
2107
2108
0
  (void)arg1;
2109
2110
0
  switch (cmd)
2111
0
  {
2112
0
    default :
2113
0
        return (0);
2114
2115
0
    case BIO_CTRL_RESET :
2116
0
        BIO_set_data(h, NULL);
2117
0
  return (0);
2118
2119
0
    case BIO_C_SET_FILE_PTR :
2120
0
        BIO_set_data(h, arg2);
2121
0
        BIO_set_init(h, 1);
2122
0
  return (1);
2123
2124
0
    case BIO_C_GET_FILE_PTR :
2125
0
        if (arg2)
2126
0
  {
2127
0
    *((void **)arg2) = BIO_get_data(h);
2128
0
    return (1);
2129
0
  }
2130
0
  else
2131
0
    return (0);
2132
2133
0
    case BIO_CTRL_DUP :
2134
0
    case BIO_CTRL_FLUSH :
2135
0
        return (1);
2136
0
  }
2137
0
}
2138
2139
2140
//
2141
// 'http_bio_free()' - Free OpenSSL data.
2142
//
2143
2144
static int        // O - 1 on success, 0 on failure
2145
http_bio_free(BIO *h)     // I - BIO data
2146
0
{
2147
0
  DEBUG_printf("8http_bio_free(h=%p)", (void *)h);
2148
2149
0
  if (!h)
2150
0
    return (0);
2151
2152
0
  if (BIO_get_shutdown(h))
2153
0
    BIO_set_init(h, 0);
2154
2155
0
  return (1);
2156
0
}
2157
2158
2159
//
2160
// 'http_bio_new()' - Initialize an OpenSSL BIO structure.
2161
//
2162
2163
static int        // O - 1 on success, 0 on failure
2164
http_bio_new(BIO *h)      // I - BIO data
2165
0
{
2166
0
  DEBUG_printf("8http_bio_new(h=%p)", (void *)h);
2167
2168
0
  if (!h)
2169
0
    return (0);
2170
2171
0
  BIO_set_init(h, 0);
2172
0
  BIO_set_data(h, NULL);
2173
2174
0
  return (1);
2175
0
}
2176
2177
2178
//
2179
// 'http_bio_puts()' - Send a string for OpenSSL.
2180
//
2181
2182
static int        // O - Bytes written
2183
http_bio_puts(BIO        *h,    // I - BIO data
2184
              const char *str)    // I - String to write
2185
0
{
2186
0
  DEBUG_printf("8http_bio_puts(h=%p, str=\"%s\")", (void *)h, str);
2187
2188
#ifdef WIN32
2189
  return (send(((http_t *)BIO_get_data(h))->fd, str, (int)strlen(str), 0));
2190
#else
2191
0
  return ((int)send(((http_t *)BIO_get_data(h))->fd, str, strlen(str), 0));
2192
0
#endif // WIN32
2193
0
}
2194
2195
2196
//
2197
// 'http_bio_read()' - Read data for OpenSSL.
2198
//
2199
2200
static int        // O - Bytes read
2201
http_bio_read(BIO  *h,      // I - BIO data
2202
              char *buf,    // I - Buffer
2203
        int  size)    // I - Number of bytes to read
2204
0
{
2205
0
  http_t  *http;      // HTTP connection
2206
0
  int   bytes;      // Bytes read
2207
2208
2209
0
  DEBUG_printf("8http_bio_read(h=%p, buf=%p, size=%d)", (void *)h, (void *)buf, size);
2210
2211
0
  http = (http_t *)BIO_get_data(h);
2212
0
  DEBUG_printf("9http_bio_read: http=%p", (void *)http);
2213
2214
0
  if (!http->blocking || http->timeout_value > 0.0)
2215
0
  {
2216
    // Make sure we have data before we read...
2217
0
    while (!_httpWait(http, http->wait_value, 0))
2218
0
    {
2219
0
      if (http->timeout_cb && (*http->timeout_cb)(http, http->timeout_data))
2220
0
  continue;
2221
2222
#ifdef WIN32
2223
      http->error = WSAETIMEDOUT;
2224
#else
2225
0
      http->error = ETIMEDOUT;
2226
0
#endif // WIN32
2227
2228
0
      DEBUG_puts("9http_bio_read: Timeout, returning -1.");
2229
0
      return (-1);
2230
0
    }
2231
0
  }
2232
2233
0
  bytes = (int)recv(http->fd, buf, (size_t)size, 0);
2234
0
  DEBUG_printf("9http_bio_read: Returning %d.", bytes);
2235
2236
0
  return (bytes);
2237
0
}
2238
2239
2240
//
2241
// 'http_bio_write()' - Write data for OpenSSL.
2242
//
2243
2244
static int        // O - Bytes written
2245
http_bio_write(BIO        *h,   // I - BIO data
2246
               const char *buf,   // I - Buffer to write
2247
         int        num)    // I - Number of bytes to write
2248
0
{
2249
0
  int bytes;        // Bytes written
2250
2251
2252
0
  DEBUG_printf("8http_bio_write(h=%p, buf=%p, num=%d)", (void *)h, (void *)buf, num);
2253
2254
0
  bytes = (int)send(((http_t *)BIO_get_data(h))->fd, buf, (size_t)num, 0);
2255
2256
0
  DEBUG_printf("9http_bio_write: Returning %d.", bytes);
2257
0
  return (bytes);
2258
0
}
2259
2260
2261
//
2262
// 'openssl_add_ext()' - Add an extension.
2263
//
2264
2265
static bool       // O - `true` on success, `false` on error
2266
openssl_add_ext(
2267
    STACK_OF(X509_EXTENSION) *exts, // I - Stack of extensions
2268
    int                      nid, // I - Extension ID
2269
    const char               *value)  // I - Value
2270
0
{
2271
0
  X509_EXTENSION *ext = NULL;   // Extension
2272
2273
2274
0
  DEBUG_printf("3openssl_add_ext(exts=%p, nid=%d, value=\"%s\")", (void *)exts, nid, value);
2275
2276
  // Create and add the extension...
2277
0
  if ((ext = X509V3_EXT_conf_nid(/*conf*/NULL, /*ctx*/NULL, nid, value)) == NULL)
2278
0
  {
2279
0
    DEBUG_puts("4openssl_add_ext: Unable to create extension, returning false.");
2280
0
    return (false);
2281
0
  }
2282
2283
0
  sk_X509_EXTENSION_push(exts, ext);
2284
2285
0
  return (true);
2286
0
}
2287
2288
2289
//
2290
// 'openssl_create_key()' - Create a suitable key pair for a certificate/signing request.
2291
//
2292
2293
static EVP_PKEY *     // O - Key pair
2294
openssl_create_key(
2295
    cups_credtype_t type)   // I - Type of key
2296
0
{
2297
0
  EVP_PKEY  *pkey;      // Key pair
2298
0
  EVP_PKEY_CTX  *ctx;     // Key generation context
2299
0
  int   algid;      // Algorithm NID
2300
0
  int   bits = 0;   // Bits
2301
0
  int   curveid = 0;    // Curve NID
2302
2303
2304
0
  switch (type)
2305
0
  {
2306
0
    case CUPS_CREDTYPE_ECDSA_P256_SHA256 :
2307
0
        algid   = EVP_PKEY_EC;
2308
0
        curveid = NID_secp256k1;
2309
0
  break;
2310
2311
0
    case CUPS_CREDTYPE_ECDSA_P384_SHA256 :
2312
0
        algid   = EVP_PKEY_EC;
2313
0
        curveid = NID_secp384r1;
2314
0
  break;
2315
2316
0
    case CUPS_CREDTYPE_ECDSA_P521_SHA256 :
2317
0
        algid   = EVP_PKEY_EC;
2318
0
        curveid = NID_secp521r1;
2319
0
  break;
2320
2321
0
    case CUPS_CREDTYPE_RSA_2048_SHA256 :
2322
0
        algid = EVP_PKEY_RSA;
2323
0
        bits  = 2048;
2324
0
  break;
2325
2326
0
    default :
2327
0
    case CUPS_CREDTYPE_RSA_3072_SHA256 :
2328
0
        algid = EVP_PKEY_RSA;
2329
0
        bits  = 3072;
2330
0
  break;
2331
2332
0
    case CUPS_CREDTYPE_RSA_4096_SHA256 :
2333
0
        algid = EVP_PKEY_RSA;
2334
0
        bits  = 4096;
2335
0
  break;
2336
0
  }
2337
2338
0
  pkey = NULL;
2339
2340
0
  if ((ctx = EVP_PKEY_CTX_new_id(algid, NULL)) == NULL)
2341
0
    _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Unable to create private key context."), 1);
2342
0
  else if (EVP_PKEY_keygen_init(ctx) <= 0)
2343
0
    _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Unable to initialize private key context."), 1);
2344
0
  else if (bits && EVP_PKEY_CTX_set_rsa_keygen_bits(ctx, bits) <= 0)
2345
0
    _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Unable to configure private key context."), 1);
2346
0
  else if (curveid && EVP_PKEY_CTX_set_ec_paramgen_curve_nid(ctx, curveid) <= 0)
2347
0
    _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Unable to configure private key context."), 1);
2348
0
  else if (EVP_PKEY_keygen(ctx, &pkey) <= 0)
2349
0
    _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Unable to create private key."), 1);
2350
2351
0
  EVP_PKEY_CTX_free(ctx);
2352
2353
0
  return (pkey);
2354
0
}
2355
2356
2357
//
2358
// 'openssl_create_name()' - Create an X.509 name value for a certificate/signing request.
2359
//
2360
2361
static X509_NAME *      // O - X.509 name value
2362
openssl_create_name(
2363
    const char      *organization,  // I - Organization or `NULL` to use common name
2364
    const char      *org_unit,    // I - Organizational unit or `NULL` for none
2365
    const char      *locality,    // I - City/town or `NULL` for "Unknown"
2366
    const char      *state_province,  // I - State/province or `NULL` for "Unknown"
2367
    const char      *country,   // I - Country or `NULL` for locale-based default
2368
    const char      *common_name, // I - Common name
2369
    const char      *email)   // I - Email address or `NULL` for none
2370
0
{
2371
0
  X509_NAME *name;      // Subject/issuer name
2372
0
  cups_lang_t *language;    // Default language info
2373
0
  const char  *langname;    // Language name
2374
2375
2376
0
  language = cupsLangDefault();
2377
0
  langname = language->language;
2378
0
  name     = X509_NAME_new();
2379
0
  if (country)
2380
0
    X509_NAME_add_entry_by_txt(name, SN_countryName, MBSTRING_ASC, (unsigned char *)country, -1, -1, 0);
2381
0
  else if (strlen(langname) == 5)
2382
0
    X509_NAME_add_entry_by_txt(name, SN_countryName, MBSTRING_ASC, (unsigned char *)langname + 3, -1, -1, 0);
2383
0
  else
2384
0
    X509_NAME_add_entry_by_txt(name, SN_countryName, MBSTRING_ASC, (unsigned char *)"US", -1, -1, 0);
2385
0
  X509_NAME_add_entry_by_txt(name, SN_commonName, MBSTRING_ASC, (unsigned char *)common_name, -1, -1, 0);
2386
0
  X509_NAME_add_entry_by_txt(name, SN_organizationName, MBSTRING_ASC, (unsigned char *)(organization ? organization : common_name), -1, -1, 0);
2387
0
  X509_NAME_add_entry_by_txt(name, SN_organizationalUnitName, MBSTRING_ASC, (unsigned char *)(org_unit ? org_unit : ""), -1, -1, 0);
2388
0
  X509_NAME_add_entry_by_txt(name, SN_stateOrProvinceName, MBSTRING_ASC, (unsigned char *)(state_province ? state_province : "Unknown"), -1, -1, 0);
2389
0
  X509_NAME_add_entry_by_txt(name, SN_localityName, MBSTRING_ASC, (unsigned char *)(locality ? locality : "Unknown"), -1, -1, 0);
2390
0
  if (email && *email)
2391
0
    X509_NAME_add_entry_by_txt(name, "emailAddress", MBSTRING_ASC, (unsigned char *)email, -1, -1, 0);
2392
2393
0
  return (name);
2394
0
}
2395
2396
2397
//
2398
// 'openssl_create_san()' - Create a list of subjectAltName values for a certificate/signing request.
2399
//
2400
2401
static X509_EXTENSION *     // O - Extension
2402
openssl_create_san(
2403
    const char         *common_name,  // I - Common name
2404
    size_t             num_alt_names, // I - Number of alternate names
2405
    const char * const *alt_names)  // I - List of alternate names
2406
0
{
2407
0
  char    temp[2048],   // Temporary string
2408
0
    *tempptr;   // Pointer into temporary string
2409
0
  size_t  i;      // Looping var
2410
2411
2412
  // Add the common name
2413
0
  snprintf(temp, sizeof(temp), "DNS:%s", common_name);
2414
0
  tempptr = temp + strlen(temp);
2415
2416
0
  if (strstr(common_name, ".local") == NULL)
2417
0
  {
2418
    // Add common_name.local to the list, too...
2419
0
    char  localname[256],   // hostname.local
2420
0
    *localptr;    // Pointer into localname
2421
2422
0
    cupsCopyString(localname, common_name, sizeof(localname));
2423
0
    if ((localptr = strchr(localname, '.')) != NULL)
2424
0
      *localptr = '\0';
2425
2426
0
    snprintf(tempptr, sizeof(temp) - (size_t)(tempptr - temp), ",DNS:%s.local", localname);
2427
0
    tempptr += strlen(tempptr);
2428
0
  }
2429
2430
  // Add any alternate names...
2431
0
  for (i = 0; i < num_alt_names; i ++)
2432
0
  {
2433
0
    if (strcmp(alt_names[i], "localhost"))
2434
0
    {
2435
0
      snprintf(tempptr, sizeof(temp) - (size_t)(tempptr - temp), ",DNS:%s", alt_names[i]);
2436
0
      tempptr += strlen(tempptr);
2437
0
    }
2438
0
  }
2439
2440
  // Return the stack
2441
0
  return (X509V3_EXT_conf_nid(/*conf*/NULL, /*ctx*/NULL, NID_subject_alt_name, temp));
2442
0
}
2443
2444
2445
//
2446
// 'openssl_get_date()' - Get the notBefore or notAfter date of a certificate.
2447
//
2448
2449
static time_t       // O - UNIX time in seconds
2450
openssl_get_date(X509 *cert,    // I - Certificate
2451
                 int  which)    // I - 0 for notBefore, 1 for notAfter
2452
0
{
2453
0
  struct tm exptm;      // Expiration date components
2454
2455
2456
0
  if (which)
2457
0
    ASN1_TIME_to_tm(X509_get0_notAfter(cert), &exptm);
2458
0
  else
2459
0
    ASN1_TIME_to_tm(X509_get0_notBefore(cert), &exptm);
2460
2461
0
  return (mktime(&exptm));
2462
0
}
2463
2464
2465
#if 0
2466
//
2467
// 'openssl_load_crl()' - Load the certificate revocation list, if any.
2468
//
2469
2470
static void
2471
openssl_load_crl(void)
2472
{
2473
  cupsMutexLock(&tls_mutex);
2474
2475
  if (!openssl_x509_crl_init(&tls_crl))
2476
  {
2477
    cups_file_t   *fp;    // CRL file
2478
    char    filename[1024], // site.crl
2479
      line[256];  // Base64-encoded line
2480
    unsigned char *data = NULL; // Buffer for cert data
2481
    size_t    alloc_data = 0, // Bytes allocated
2482
      num_data = 0; // Bytes used
2483
    int     decoded;  // Bytes decoded
2484
    openssl_datum_t datum;    // Data record
2485
2486
2487
    http_make_path(filename, sizeof(filename), CUPS_SERVERROOT, "site", "crl");
2488
2489
    if ((fp = cupsFileOpen(filename, "r")) != NULL)
2490
    {
2491
      while (cupsFileGets(fp, line, sizeof(line)))
2492
      {
2493
  if (!strcmp(line, "-----BEGIN X509 CRL-----"))
2494
  {
2495
    if (num_data)
2496
    {
2497
     /*
2498
      * Missing END X509 CRL...
2499
      */
2500
2501
      break;
2502
    }
2503
  }
2504
  else if (!strcmp(line, "-----END X509 CRL-----"))
2505
  {
2506
    if (!num_data)
2507
    {
2508
     /*
2509
      * Missing data...
2510
      */
2511
2512
      break;
2513
    }
2514
2515
          datum.data = data;
2516
    datum.size = num_data;
2517
2518
    openssl_x509_crl_import(tls_crl, &datum, GNUTLS_X509_FMT_PEM);
2519
2520
    num_data = 0;
2521
  }
2522
  else
2523
  {
2524
    if (alloc_data == 0)
2525
    {
2526
      data       = malloc(2048);
2527
      alloc_data = 2048;
2528
2529
      if (!data)
2530
        break;
2531
    }
2532
    else if ((num_data + strlen(line)) >= alloc_data)
2533
    {
2534
      unsigned char *tdata = realloc(data, alloc_data + 1024);
2535
              // Expanded buffer
2536
2537
      if (!tdata)
2538
        break;
2539
2540
      data       = tdata;
2541
      alloc_data += 1024;
2542
    }
2543
2544
    decoded = alloc_data - num_data;
2545
    httpDecode64((char *)data + num_data, &decoded, line, NULL);
2546
    num_data += (size_t)decoded;
2547
  }
2548
      }
2549
2550
      cupsFileClose(fp);
2551
2552
      if (data)
2553
  free(data);
2554
    }
2555
  }
2556
2557
  cupsMutexUnlock(&tls_mutex);
2558
}
2559
#endif // 0
2560
2561
2562
//
2563
// 'openssl_load_x509()' - Load a stack of X.509 certificates.
2564
//
2565
2566
static STACK_OF(X509) *     // O - Stack of X.509 certificates
2567
openssl_load_x509(
2568
    const char *credentials)    // I - Credentials string
2569
0
{
2570
0
  STACK_OF(X509)  *certs = NULL; // Certificate chain
2571
0
  X509      *cert = NULL; // Current certificate
2572
0
  BIO     *bio;   // Basic I/O for string
2573
2574
2575
  // Range check input...
2576
0
  DEBUG_printf("4openssl_load_x509(credentials=\"%s\")", credentials);
2577
0
  if (!credentials || !*credentials)
2578
0
    return (NULL);
2579
2580
  // Make a BIO memory buffer for the string...
2581
0
  if ((bio = BIO_new_mem_buf(credentials, strlen(credentials))) == NULL)
2582
0
    return (NULL);
2583
2584
  // Read all the X509 certificates from the string...
2585
0
  while (PEM_read_bio_X509(bio, &cert, NULL, (void *)""))
2586
0
  {
2587
0
    if (!certs)
2588
0
    {
2589
      // Make a new stack of X509 certs...
2590
0
      certs = sk_X509_new_null();
2591
0
    }
2592
2593
0
    if (certs)
2594
0
    {
2595
      // Add the X509 certificate...
2596
0
      sk_X509_push(certs, cert);
2597
0
    }
2598
0
    else
2599
0
    {
2600
      // Unable to add, free and stop...
2601
0
      X509_free(cert);
2602
0
      break;
2603
0
    }
2604
2605
0
    cert = NULL;
2606
0
  }
2607
2608
0
  BIO_free(bio);
2609
2610
0
  return (certs);
2611
0
}
2612
2613
2614
//
2615
// 'openssl_validate_name()' - Check that the certificate is valid for the given name.
2616
//
2617
2618
static bool       // O - `true` if valid, `false` otherwise
2619
openssl_validate_name(
2620
    X509       *cert,     // I - Certificate
2621
    const char *common_name)    // I - Common name
2622
0
{
2623
0
  bool    result = false;    // Return value
2624
0
  char    subjectName[256]; // Common name from certificate
2625
0
  STACK_OF(GENERAL_NAME) *names = NULL;
2626
              // subjectAltName values
2627
2628
2629
0
  if (X509_NAME_get_text_by_NID(X509_get_subject_name(cert), NID_commonName, subjectName, sizeof(subjectName)) < 0)
2630
0
    cupsCopyString(subjectName, "unknown", sizeof(subjectName));
2631
2632
0
  DEBUG_printf("1openssl_validate_name: subjectName=\"%s\"", subjectName);
2633
2634
0
  if (!_cups_strcasecmp(common_name, subjectName))
2635
0
  {
2636
0
    DEBUG_puts("1openssl_validate_name: Match.");
2637
0
    return (true);
2638
0
  }
2639
2640
0
  if ((names = X509_get_ext_d2i(cert, NID_subject_alt_name, /*crit*/NULL, /*idx*/NULL)) != NULL)
2641
0
  {
2642
    // Got subjectAltName values, look at them...
2643
0
    int i,        // Looping var
2644
0
  count;        // Number of values
2645
2646
0
    DEBUG_printf("1openssl_validate_name: names=%p", names);
2647
0
    for (i = 0, count = sk_GENERAL_NAME_num(names); i < count && !result; i ++)
2648
0
    {
2649
0
      const GENERAL_NAME *name = sk_GENERAL_NAME_value(names, i);
2650
          // subjectAltName value
2651
2652
0
      if (!name)
2653
0
  continue;
2654
2655
0
      DEBUG_printf("1openssl_validate_name: subjectAltName[%d/%d].type=%d", i + 1, count, name->type);
2656
0
      if (name->type == GEN_DNS)
2657
0
      {
2658
  // Match a DNS name...
2659
0
  char  *dNSName;   // DNS name value
2660
2661
0
  if (ASN1_STRING_to_UTF8((unsigned char **)&dNSName, name->d.dNSName) > 0)
2662
0
  {
2663
0
    DEBUG_printf("1openssl_validate_name: subjectAltName[%d/%d].dNSName=\"%s\"", i + 1, count, dNSName);
2664
2665
0
    if (!_cups_strcasecmp(common_name, dNSName))
2666
0
    {
2667
      // Direct name match...
2668
0
      DEBUG_puts("1openssl_validate_name: Match.");
2669
0
      result = true;
2670
0
    }
2671
0
    else if (!strncmp(dNSName, "*.", 2))
2672
0
    {
2673
      // Compare wildcard...
2674
0
      const char *domain_name = strchr(common_name, '.');
2675
              // Domain name of common name
2676
0
      if (domain_name && !_cups_strcasecmp(domain_name, dNSName + 1))
2677
0
      {
2678
0
        DEBUG_puts("1openssl_validate_name: Match.");
2679
0
        result = true;
2680
0
      }
2681
0
    }
2682
2683
0
    OPENSSL_free(dNSName);
2684
0
  }
2685
0
      }
2686
0
    }
2687
2688
0
    GENERAL_NAMES_free(names);
2689
0
  }
2690
2691
0
  return (result);
2692
0
}