XRootD
XrdCryptosslgsiAux.cc
Go to the documentation of this file.
1 /******************************************************************************/
2 /* */
3 /* X r d C r y p t o s s l g s i A u x . h h */
4 /* */
5 /* (c) 2005, G. Ganis / CERN */
6 /* */
7 /* This file is part of the XRootD software suite. */
8 /* */
9 /* XRootD is free software: you can redistribute it and/or modify it under */
10 /* the terms of the GNU Lesser General Public License as published by the */
11 /* Free Software Foundation, either version 3 of the License, or (at your */
12 /* option) any later version. */
13 /* */
14 /* XRootD is distributed in the hope that it will be useful, but WITHOUT */
15 /* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or */
16 /* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public */
17 /* License for more details. */
18 /* */
19 /* You should have received a copy of the GNU Lesser General Public License */
20 /* along with XRootD in a file called COPYING.LESSER (LGPL license) and file */
21 /* COPYING (GPL license). If not, see <http://www.gnu.org/licenses/>. */
22 /* */
23 /* The copyright holder's institutional names and contributor's names may not */
24 /* be used to endorse or promote products derived from this software without */
25 /* specific prior written permission of the institution or contributor. */
26 /* */
27 /******************************************************************************/
28 
29 /* ************************************************************************** */
30 /* */
31 /* GSI utility functions */
32 /* */
33 /* ************************************************************************** */
34 #include <cstring>
35 #include <sys/types.h>
36 #include <sys/stat.h>
37 
38 #include <openssl/asn1.h>
39 #include <openssl/asn1t.h>
40 #include <openssl/err.h>
41 #include <openssl/evp.h>
42 #include <openssl/pem.h>
43 #include <openssl/rsa.h>
44 #include <openssl/x509v3.h>
45 #include <memory>
46 
47 #include "XrdSut/XrdSutRndm.hh"
54 
55 //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
56 // //
57 // type aliases to ease use of smart pointers with common ssl structures //
58 // //
59 //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
60 static void stackOfX509ExtensionDelete(STACK_OF(X509_EXTENSION) *ske) {
61  sk_X509_EXTENSION_pop_free(ske, X509_EXTENSION_free);
62 }
63 using EVP_PKEY_ptr = std::unique_ptr<EVP_PKEY, decltype(&EVP_PKEY_free)>;
64 using X509_ptr = std::unique_ptr<X509, decltype(&X509_free)>;
65 using X509_NAME_ptr = std::unique_ptr<X509_NAME, decltype(&X509_NAME_free)>;
66 using X509_REQ_ptr = std::unique_ptr<X509_REQ, decltype(&X509_REQ_free)>;
67 using X509_EXTENSION_ptr = std::unique_ptr<X509_EXTENSION, decltype(&X509_EXTENSION_free)>;
68 using PROXY_CERT_INFO_EXTENSION_ptr = std::unique_ptr<PROXY_CERT_INFO_EXTENSION, decltype(&PROXY_CERT_INFO_EXTENSION_free)>;
69 using STACK_OF_X509_EXTENSION_ptr = std::unique_ptr<STACK_OF(X509_EXTENSION), decltype(&stackOfX509ExtensionDelete)>;
70 
71 //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
72 // //
73 // Extensions OID relevant for proxies //
74 // //
75 //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
76 
77 // X509v3 Key Usage: critical
78 #define KEY_USAGE_OID "2.5.29.15"
79 // X509v3 Subject Alternative Name: must be absent
80 #define SUBJ_ALT_NAME_OID "2.5.29.17"
81 
82 //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
83 // //
84 // VOMS relevant stuff //
85 // //
86 //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
87 
88 #define XRDGSI_VOMS_ATCAP_OID "1.3.6.1.4.1.8005.100.100.4"
89 #define XRDGSI_VOMS_ACSEQ_OID "1.3.6.1.4.1.8005.100.100.5"
90 
91 #define BIO_PRINT(b,c) \
92  BUF_MEM *bptr; \
93  BIO_get_mem_ptr(b, &bptr); \
94  if (bptr) { \
95  char *s = new char[bptr->length+1]; \
96  memcpy(s, bptr->data, bptr->length); \
97  s[bptr->length] = '\0'; \
98  PRINT(c << s); \
99  delete [] s; \
100  } else { \
101  PRINT("ERROR: "<<c<<" BIO internal buffer undefined!"); \
102  } \
103  if (b) BIO_free(b);
104 
105 #define BIO_GET_STRING(b,str) \
106  BUF_MEM *bptr; \
107  BIO_get_mem_ptr(b, &bptr); \
108  if (bptr) { \
109  char *s = new char[bptr->length+1]; \
110  memcpy(s, bptr->data, bptr->length); \
111  s[bptr->length] = '\0'; \
112  str = s; \
113  delete [] s; \
114  } else { \
115  PRINT("ERROR: GET_STRING: BIO internal buffer undefined!"); \
116  } \
117  if (b) BIO_free(b);
118 
119 static int XrdCheckRSA (EVP_PKEY *pkey) {
120  int rc;
121  EVP_PKEY_CTX *ckctx = EVP_PKEY_CTX_new(pkey, 0);
122  rc = EVP_PKEY_check(ckctx);
123  EVP_PKEY_CTX_free(ckctx);
124  return rc;
125 }
126 
127 int XrdCryptosslX509Asn1PrintInfo(int tag, int xclass, int constructed, int indent);
128 int XrdCryptosslX509FillUnknownExt(const unsigned char **pp, long length);
129 int XrdCryptosslX509FillVOMS(const unsigned char **pp,
130  long length, bool &getvat, XrdOucString &vat);
131 
132 //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
133 // //
134 // Handlers of the ProxyCertInfo extension following RFC3820 //
135 // //
136 //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
137 
138 ASN1_SEQUENCE(PROXY_CERT_INFO_EXTENSION_OLD) =
139 {
140  ASN1_SIMPLE(PROXY_CERT_INFO_EXTENSION, proxyPolicy, PROXY_POLICY),
141  ASN1_EXP_OPT(PROXY_CERT_INFO_EXTENSION, pcPathLengthConstraint, ASN1_INTEGER, 1)
142 } ASN1_SEQUENCE_END_name(PROXY_CERT_INFO_EXTENSION, PROXY_CERT_INFO_EXTENSION_OLD)
143 
144 IMPLEMENT_ASN1_ENCODE_FUNCTIONS_fname(PROXY_CERT_INFO_EXTENSION, PROXY_CERT_INFO_EXTENSION_OLD, PROXY_CERT_INFO_EXTENSION_OLD)
145 
146 //___________________________________________________________________________
147 bool XrdCryptosslProxyCertInfo(const void *extdata, int &pathlen, bool *haspolicy)
148 {
149  //
150  // Check presence of a proxyCertInfo and retrieve the path length constraint.
151  // Written following RFC3820, examples in openssl-<vers>/crypto source code.
152  // in gridsite code and Globus proxycertinfo.h / .c.
153  // if 'haspolicy' is defined, the existence of a policy field is checked;
154  // the content ignored for the time being.
155 
156  // Make sure we got an extension
157  if (!extdata) {
158  return 0;
159  }
160  // Structure the buffer
161  X509_EXTENSION *ext = (X509_EXTENSION *)extdata;
162 
163  // Check ProxyCertInfo OID
164  char s[80] = {0};
165  OBJ_obj2txt(s, sizeof(s), X509_EXTENSION_get_object(ext), 1);
166 
167  // Now extract the path length constraint, if any
168  const unsigned char *p = ASN1_STRING_get0_data(X509_EXTENSION_get_data(ext));
169  PROXY_CERT_INFO_EXTENSION *pci = 0;
170  if (!strcmp(s, gsiProxyCertInfo_OID))
171  pci = d2i_PROXY_CERT_INFO_EXTENSION(0, &p, ASN1_STRING_length(X509_EXTENSION_get_data(ext)));
172  else if (!strcmp(s, gsiProxyCertInfo_OLD_OID))
173  pci = d2i_PROXY_CERT_INFO_EXTENSION_OLD(0, &p, ASN1_STRING_length(X509_EXTENSION_get_data(ext)));
174  if (!pci) {
175  return 0;
176  }
177 
178  // Default length is -1, i.e. check disabled
179  pathlen = -1;
180  if (pci->pcPathLengthConstraint) {
181  pathlen = ASN1_INTEGER_get(pci->pcPathLengthConstraint);
182  }
183 
184  // If required, check the existence of a policy field
185  if (haspolicy) {
186  *haspolicy = (pci->proxyPolicy) ? 1 : 0;
187  }
188 
189  // We are done
190  return 1;
191 }
192 
193 //___________________________________________________________________________
194 void XrdCryptosslSetPathLenConstraint(void *extdata, int pathlen)
195 {
196  //
197  // Set the patch length constraint valur in proxyCertInfo extension ext
198  // to 'pathlen'.
199 
200  // Make sure we got an extension
201  if (!extdata)
202  return;
203  // Structure the buffer
204  X509_EXTENSION *ext = (X509_EXTENSION *)extdata;
205 
206  // Check ProxyCertInfo OID
207  char s[80] = {0};
208  OBJ_obj2txt(s, sizeof(s), X509_EXTENSION_get_object(ext), 1);
209 
210  // Now extract the path length constraint, if any
211  const unsigned char *p = ASN1_STRING_get0_data(X509_EXTENSION_get_data(ext));
212  PROXY_CERT_INFO_EXTENSION *pci = 0;
213  if (!strcmp(s, gsiProxyCertInfo_OID))
214  pci = d2i_PROXY_CERT_INFO_EXTENSION(0, &p, ASN1_STRING_length(X509_EXTENSION_get_data(ext)));
215  else if (!strcmp(s, gsiProxyCertInfo_OLD_OID))
216  pci = d2i_PROXY_CERT_INFO_EXTENSION_OLD(0, &p, ASN1_STRING_length(X509_EXTENSION_get_data(ext)));
217  if (!pci)
218  return;
219 
220  // Set the new length
221  if (pci->pcPathLengthConstraint) {
222  ASN1_INTEGER_set(pci->pcPathLengthConstraint, pathlen);
223  }
224 
225  // We are done
226  return;
227 }
228 
229 //____________________________________________________________________________
230 int XrdCryptosslX509CreateProxy(const char *fnc, const char *fnk,
231  XrdProxyOpt_t *pxopt,
233  const char *fnp)
234 {
235  // Create a proxy certificate following the GSI specification (RFC 3820)
236  // for the EEC certificate in file 'fnc', private key in 'fnk'.
237  // A chain containing the proxy certificate and the EEC is returned in 'xp'
238  // and its full RSA key in 'kp'.
239  // The structure pxopt can be used to change the default options about
240  // number of bits for the key, duration validity and max path signature depth.
241  // If 'fpn' is defined, a PEM file is created with, in order, the proxy
242  // certificate, the related private key and the EEC certificate (standard
243  // GSI format).
244  // Policy fields in the CertProxyExtension not yet included.
245  // Return 0 in case of success, < 0 otherwise
246  EPNAME("X509CreateProxy");
247 
248  // Make sure the files are specified
249  if (!fnc || !fnk || !xp || !kp) {
250  PRINT("invalid inputs ");
251  return -1;
252  }
253 
254  //
255  // Init OpenSSL
256  OpenSSL_add_all_ciphers();
257  OpenSSL_add_all_digests();
258  ERR_load_crypto_strings();
259 
260  // Use default options, if not specified
261  int bits = (pxopt && pxopt->bits >= XrdCryptoMinRSABits) ? pxopt->bits : XrdCryptoDefRSABits;
262  int valid = (pxopt) ? pxopt->valid : 43200; // 12 hours
263  int depthlen = (pxopt) ? pxopt->depthlen : -1; // unlimited
264 
265  //
266  // Get EEC certificate from fnc
267  X509 *xEEC = 0;
268  FILE *fc = fopen(fnc, "r");
269  if (fc) {
270  // Read out the certificate
271  if (PEM_read_X509(fc, &xEEC, 0, 0)) {
272  DEBUG("EEC certificate loaded from file: "<<fnc);
273  } else {
274  PRINT("unable to load EEC certificate from file: "<<fnc);
275  fclose(fc);
276  return -kErrPX_BadEECfile;
277  }
278  } else {
279  PRINT("EEC certificate cannot be opened (file: "<<fnc<<")");
280  return -kErrPX_BadEECfile;
281  }
282  fclose(fc);
283  // Make sure the certificate is not expired
284  int now = (int)time(0);
285  if (now > XrdCryptosslASN1toUTC(X509_get_notAfter(xEEC))) {
286  PRINT("EEC certificate has expired");
287  X509_free(xEEC);
288  return -kErrPX_ExpiredEEC;
289  }
290 
291  //
292  // Get EEC private key from fnk
293  EVP_PKEY *ekEEC = 0;
294  FILE *fk = fopen(fnk, "r");
295  if (fk) {
296  // Read out the private key
297  XrdOucString sbj;
298  XrdCryptosslNameOneLine(X509_get_subject_name(xEEC), sbj);
299  PRINT("Your identity: "<<sbj);
300  if ((PEM_read_PrivateKey(fk, &ekEEC, 0, 0))) {
301  DEBUG("EEC private key loaded from file: "<<fnk);
302  } else {
303  PRINT("unable to load EEC private key from file: "<<fnk);
304  fclose(fk);
305  X509_free(xEEC);
306  return -kErrPX_BadEECfile;
307  }
308  } else {
309  PRINT("EEC private key file cannot be opened (file: "<<fnk<<")");
310  X509_free(xEEC);
311  return -kErrPX_BadEECfile;
312  }
313  fclose(fk);
314  // Check key consistency
315  if (XrdCheckRSA(ekEEC) != 1) {
316  PRINT("inconsistent key loaded");
317  EVP_PKEY_free(ekEEC);
318  X509_free(xEEC);
319  return -kErrPX_BadEECkey;
320  }
321  //
322  // Create a new request
323  X509_REQ *preq = X509_REQ_new();
324  if (!preq) {
325  PRINT("cannot to create cert request");
326  EVP_PKEY_free(ekEEC);
327  X509_free(xEEC);
328  return -kErrPX_NoResources;
329  }
330  //
331  // Create the new PKI for the proxy (exponent 65537)
332  BIGNUM *e = BN_new();
333  if (!e) {
334  PRINT("proxy key could not be generated - return");
335  EVP_PKEY_free(ekEEC);
336  X509_free(xEEC);
337  return -kErrPX_GenerateKey;
338  }
339  BN_set_word(e, 0x10001);
340  EVP_PKEY *ekPX = 0;
341  EVP_PKEY_CTX *pkctx = EVP_PKEY_CTX_new_id(EVP_PKEY_RSA, 0);
342  EVP_PKEY_keygen_init(pkctx);
343  EVP_PKEY_CTX_set_rsa_keygen_bits(pkctx, bits);
344 #if OPENSSL_VERSION_NUMBER >= 0x30000000L
345  EVP_PKEY_CTX_set1_rsa_keygen_pubexp(pkctx, e);
346  BN_free(e);
347 #else
348  EVP_PKEY_CTX_set_rsa_keygen_pubexp(pkctx, e);
349 #endif
350  EVP_PKEY_keygen(pkctx, &ekPX);
351  EVP_PKEY_CTX_free(pkctx);
352  if (!ekPX) {
353  PRINT("proxy key could not be generated - return");
354  EVP_PKEY_free(ekEEC);
355  X509_free(xEEC);
356  return -kErrPX_GenerateKey;
357  }
358  X509_REQ_set_pubkey(preq, ekPX);
359  //
360  // Generate a serial number. Specification says that this *should*
361  // unique, so we just draw an unsigned random integer
362  unsigned int serial = XrdSutRndm::GetUInt();
363  //
364  // The subject name is the certificate subject + /CN=<rand_uint>
365  // with <rand_uint> is a random unsigned int used also as serial
366  // number.
367  // Duplicate user subject name
368  X509_NAME *psubj = X509_NAME_dup(X509_get_subject_name(xEEC));
369  // Create an entry with the common name
370  unsigned char sn[20] = {0};
371  sprintf((char *)sn, "%d", serial);
372  if (!X509_NAME_add_entry_by_txt(psubj, (char *)"CN", MBSTRING_ASC,
373  sn, -1, -1, 0)) {
374  PRINT("could not add CN - (serial: "<<serial<<", sn: "<<sn<<")");
375  return -kErrPX_SetAttribute;
376  }
377  //
378  // Set the name
379  if (X509_REQ_set_subject_name(preq, psubj) != 1) {
380  PRINT("could not set subject name - return");
381  return -kErrPX_SetAttribute;
382  }
383 
384  //
385  // Create the extension CertProxyInfo
386  PROXY_CERT_INFO_EXTENSION *pci = PROXY_CERT_INFO_EXTENSION_new();
387  if (!pci) {
388  PRINT("could not create structure for extension - return");
389  return -kErrPX_NoResources;
390  }
391  pci->proxyPolicy->policyLanguage = OBJ_txt2obj("1.3.6.1.5.5.7.21.1", 1);
392  //
393  // Set the new length
394  if (depthlen > -1) {
395  if ((pci->pcPathLengthConstraint = ASN1_INTEGER_new())) {
396  ASN1_INTEGER_set(pci->pcPathLengthConstraint, depthlen);
397  } else {
398  PRINT("could not set the path length contrain");
399  return -kErrPX_SetPathDepth;
400  }
401  }
402 
403  //
404  // create extension
405  X509_EXTENSION *ext = X509_EXTENSION_new();
406  if (!ext) {
407  PRINT("could not create extension object");
408  return -kErrPX_NoResources;
409  }
410  // Set extension name.
411  ASN1_OBJECT *obj = OBJ_txt2obj(gsiProxyCertInfo_OID, 1);
412  if (!obj || X509_EXTENSION_set_object(ext, obj) != 1) {
413  PRINT("could not set extension name");
414  return -kErrPX_SetAttribute;
415  }
416  // flag as critical
417  if (X509_EXTENSION_set_critical(ext, 1) != 1) {
418  PRINT("could not set extension critical flag");
419  return -kErrPX_SetAttribute;
420  }
421  // Extract data in format for extension
422  int len = i2d_PROXY_CERT_INFO_EXTENSION(pci, 0);
423  unsigned char *data = (unsigned char *) malloc(len);
424  if (!data) {
425  PRINT("could not allocate data field for extension");
426  return -kErrPX_NoResources;
427  }
428  unsigned char *pp = data;
429  if ((i2d_PROXY_CERT_INFO_EXTENSION(pci, &pp)) <= 0) {
430  PRINT("problem converting data for extension");
431  free(data);
432  return -kErrPX_Error;
433  }
434  ASN1_OCTET_STRING *os = ASN1_OCTET_STRING_new();
435  if (!os) {
436  PRINT("could not allocate data field for extension");
437  free(data);
438  return -kErrPX_NoResources;
439  }
440  if (ASN1_OCTET_STRING_set(os, data, len) == 0) {
441  PRINT("could not allocate data field for extension");
442  ASN1_STRING_free(os);
443  free(data);
444  return -kErrPX_NoResources;
445  }
446  free(data);
447  if (X509_EXTENSION_set_data(ext, os) == 0) {
448  PRINT("could not allocate data field for extension");
449  ASN1_STRING_free(os);
450  return -kErrPX_NoResources;
451  }
452  ASN1_STRING_free(os);
453  // Create a stack
454  STACK_OF(X509_EXTENSION) *esk = sk_X509_EXTENSION_new_null();
455  if (!esk) {
456  PRINT("could not create stack for extensions");
457  return -kErrPX_NoResources;
458  }
459  //
460  // Now we add the new extension
461  if (sk_X509_EXTENSION_push(esk, ext) == 0) {
462  PRINT("could not push the extension in the stack");
463  return -kErrPX_Error;
464  }
465  // Add extension
466  if (!(X509_REQ_add_extensions(preq, esk))) {
467  PRINT("problem adding extension");
468  return -kErrPX_SetAttribute;
469  }
470  //
471  // Sign the request
472  if (!(X509_REQ_sign(preq, ekPX, EVP_sha256()))) {
473  PRINT("problems signing the request");
474  return -kErrPX_Signing;
475  }
476  //
477  // Create new proxy cert
478  X509 *xPX = X509_new();
479  if (!xPX) {
480  PRINT("could not create certificate object for proxies");
481  return -kErrPX_NoResources;
482  }
483 
484  // Set version number
485  if (X509_set_version(xPX, 2L) != 1) {
486  PRINT("could not set version");
487  return -kErrPX_SetAttribute;
488  }
489 
490  // Set serial number
491  if (ASN1_INTEGER_set(X509_get_serialNumber(xPX), serial) != 1) {
492  PRINT("could not set serial number");
493  return -kErrPX_SetAttribute;
494  }
495 
496  // Set subject name
497  if (X509_set_subject_name(xPX, psubj) != 1) {
498  PRINT("could not set subject name");
499  return -kErrPX_SetAttribute;
500  }
501  X509_NAME_free(psubj);
502 
503  // Set issuer name
504  if (X509_set_issuer_name(xPX, X509_get_subject_name(xEEC)) != 1) {
505  PRINT("could not set issuer name");
506  return -kErrPX_SetAttribute;
507  }
508 
509  // Set public key
510  if (X509_set_pubkey(xPX, ekPX) != 1) {
511  PRINT("could not set issuer name");
512  return -kErrPX_SetAttribute;
513  }
514 
515  // Set proxy validity: notBefore now
516  if (!X509_gmtime_adj(X509_get_notBefore(xPX), 0)) {
517  PRINT("could not set notBefore");
518  return -kErrPX_SetAttribute;
519  }
520 
521  // Set proxy validity: notAfter expire_secs from now
522  if (!X509_gmtime_adj(X509_get_notAfter(xPX), valid)) {
523  PRINT("could not set notAfter");
524  return -kErrPX_SetAttribute;
525  }
526 
527  // First duplicate the extensions of the EE certificate
528 #if OPENSSL_VERSION_NUMBER < 0x40000000L
529  X509_EXTENSION *xEECext = 0;
530 #else
531  const X509_EXTENSION *xEECext = 0;
532 #endif
533  int nEECext = X509_get_ext_count(xEEC);
534  DEBUG("number of extensions found in the original certificate: "<< nEECext);
535  int i = 0;
536  bool haskeyusage = 0;
537  for (i = 0; i< nEECext; i++) {
538  xEECext = X509_get_ext(xEEC, i);
539  char s[256];
540  OBJ_obj2txt(s, sizeof(s), X509_EXTENSION_get_object(xEECext), 1);
541  // Flag key usage extension
542  if (!haskeyusage && !strcmp(s, KEY_USAGE_OID)) haskeyusage = 1;
543  // Skip subject alternative name extension
544  if (!strcmp(s, SUBJ_ALT_NAME_OID)) continue;
545  // Duplicate and add to the stack
546  X509_EXTENSION *xEECextdup = X509_EXTENSION_dup(xEECext);
547  if (X509_add_ext(xPX, xEECextdup, -1) == 0) {
548  PRINT("could not push the extension '"<<s<<"' in the stack");
549  return -kErrPX_Error;
550  }
551  // Notify what we added
552  int crit = X509_EXTENSION_get_critical(xEECextdup);
553  DEBUG("added extension '"<<s<<"', critical: " << crit);
554  }
555 
556  // Warn if the critical oen is missing
557  if (!haskeyusage) {
558  PRINT(">>> WARNING: critical extension 'Key Usage' not found in original certificate! ");
559  PRINT(">>> WARNING: this proxy may not be accepted by some parsers. ");
560  }
561 
562  // Add the extension
563  if (X509_add_ext(xPX, ext, -1) != 1) {
564  PRINT("could not add extension");
565  return -kErrPX_SetAttribute;
566  }
567 
568  //
569  // Sign the certificate
570  if (!(X509_sign(xPX, ekEEC, EVP_sha256()))) {
571  PRINT("problems signing the certificate");
572  return -kErrPX_Signing;
573  }
574 
575  // Fill outputs
576  XrdCryptoX509 *xcPX = new XrdCryptosslX509(xPX);
577  if (!xcPX) {
578  PRINT("could not create container for proxy certificate");
579  return -kErrPX_NoResources;
580  }
581  // We need the full key
582  ((XrdCryptosslX509 *)xcPX)->SetPKI((XrdCryptoX509data)ekPX);
583  xp->PushBack(xcPX);
584  XrdCryptoX509 *xcEEC = new XrdCryptosslX509(xEEC);
585  if (!xcEEC) {
586  PRINT("could not create container for EEC certificate");
587  return -kErrPX_NoResources;
588  }
589  xp->PushBack(xcEEC);
590  *kp = new XrdCryptosslRSA(ekPX);
591  if (!(*kp)) {
592  PRINT("could not creatr out PKI");
593  return -kErrPX_NoResources;
594  }
595 
596  //
597  // Write to a file if requested
598  int rc = 0;
599  if (fnp) {
600  // Open the file in write mode
601  FILE *fp = fopen(fnp,"w");
602  int ifp = -1;
603  if (!fp) {
604  PRINT("cannot open file to save the proxy certificate (file: "<<fnp<<")");
605  rc = -kErrPX_ProxyFile;
606  }
607  else if ( (ifp = fileno(fp)) == -1) {
608  PRINT("got invalid file descriptor for the proxy certificate (file: "<<
609  fnp<<")");
610  fclose(fp);
611  rc = -kErrPX_ProxyFile;
612  }
613  // Set permissions to 0600
614  else if (fchmod(ifp, 0600) == -1) {
615  PRINT("cannot set permissions on file: "<<fnp<<" (errno: "<<errno<<")");
616  fclose(fp);
617  rc = -kErrPX_ProxyFile;
618  }
619  else if (!rc && PEM_write_X509(fp, xPX) != 1) {
620  PRINT("error while writing proxy certificate");
621  fclose(fp);
622  rc = -kErrPX_ProxyFile;
623  }
624  else if (!rc && PEM_write_PrivateKey(fp, ekPX, 0, 0, 0, 0, 0) != 1) {
625  PRINT("error while writing proxy private key");
626  fclose(fp);
627  rc = -kErrPX_ProxyFile;
628  }
629  else if (!rc && PEM_write_X509(fp, xEEC) != 1) {
630  PRINT("error while writing EEC certificate");
631  fclose(fp);
632  rc = -kErrPX_ProxyFile;
633  }
634  else
635  fclose(fp);
636  // Change
637  }
638 
639  // Cleanup
640  EVP_PKEY_free(ekEEC);
641  X509_REQ_free(preq);
642  sk_X509_EXTENSION_free(esk);
643 
644  // We are done
645  return rc;
646 }
647 
648 //____________________________________________________________________________
650  XrdCryptoX509Req **xcro, XrdCryptoRSA **kcro)
651 {
652  // Create a proxy certificate request following the GSI specification
653  // (RFC 3820) for the proxy certificate 'xpi'.
654  // The proxy certificate is returned in 'xpo' and its full RSA key in 'kpo'.
655  // Policy fields in the CertProxyExtension not yet included.
656  // Return 0 in case of success, < 0 otherwise
657  EPNAME("X509CreateProxyReq");
658 
659  // Make sure we got an proxy certificate as input
660  if (!xcpi || !(xcpi->Opaque())) {
661  PRINT("input proxy certificate not specified");
662  return -1;
663  }
664 
665  // Point to the cerificate
666  X509 *xpi = (X509 *)(xcpi->Opaque());
667 
668  // Make sure the certificate is not expired
669  if (!(xcpi->IsValid())) {
670  PRINT("EEC certificate has expired");
671  return -kErrPX_ExpiredEEC;
672  }
673 
674  // These will be assigned dynamically allocated ssl structures later.
675  // They use type aliases for unique_ptr, to ease use of a smart pointer.
676  //
677  EVP_PKEY_ptr ekro(nullptr, &EVP_PKEY_free);
678  X509_EXTENSION_ptr ext(nullptr, &X509_EXTENSION_free);
679  X509_NAME_ptr psubj(nullptr, &X509_NAME_free);
680  X509_REQ_ptr xro(nullptr, &X509_REQ_free);
681  PROXY_CERT_INFO_EXTENSION_ptr pci(nullptr, &PROXY_CERT_INFO_EXTENSION_free);
683 
684  //
685  // Create a new request
686  xro.reset(X509_REQ_new());
687  if (!xro) {
688  PRINT("cannot to create cert request");
689  return -kErrPX_NoResources;
690  }
691  //
692  // Use same num of bits as the signing certificate,
693  // but no less than the minimum RSA bits (2048)
694  ekro.reset(X509_get_pubkey(xpi));
695  int bits = EVP_PKEY_bits(ekro.get());
696  ekro = nullptr;
697 
698  bits = (bits < XrdCryptoMinRSABits) ? XrdCryptoDefRSABits : bits;
699  //
700  // Create the new PKI for the proxy (exponent 65537)
701  BIGNUM *e = BN_new();
702  if (!e) {
703  PRINT("proxy key could not be generated - return");
704  return -kErrPX_GenerateKey;
705  }
706  BN_set_word(e, 0x10001);
707  EVP_PKEY_CTX *pkctx = EVP_PKEY_CTX_new_id(EVP_PKEY_RSA, 0);
708  EVP_PKEY_keygen_init(pkctx);
709  EVP_PKEY_CTX_set_rsa_keygen_bits(pkctx, bits);
710 #if OPENSSL_VERSION_NUMBER >= 0x30000000L
711  EVP_PKEY_CTX_set1_rsa_keygen_pubexp(pkctx, e);
712  BN_free(e);
713 #else
714  EVP_PKEY_CTX_set_rsa_keygen_pubexp(pkctx, e);
715 #endif
716  {
717  EVP_PKEY *tmppk = nullptr;
718  EVP_PKEY_keygen(pkctx, &tmppk);
719  ekro.reset(tmppk);
720  }
721  EVP_PKEY_CTX_free(pkctx);
722  //
723  // Set the key into the request
724  if (!ekro) {
725  PRINT("proxy key could not be generated - return");
726  return -kErrPX_GenerateKey;
727  }
728  X509_REQ_set_pubkey(xro.get(), ekro.get());
729  //
730  // Generate a serial number. Specification says that this *should*
731  // unique, so we just draw an unsigned random integer
732  unsigned int serial = XrdSutRndm::GetUInt();
733  //
734  // The subject name is the certificate subject + /CN=<rand_uint>
735  // with <rand_uint> is a random unsigned int used also as serial
736  // number.
737  // Duplicate user subject name
738  psubj.reset(X509_NAME_dup(X509_get_subject_name(xpi)));
739  if (xcro && *xcro && *((int *)(*xcro)) <= 10100) {
740  // Delete existing proxy CN addition; for backward compatibility
741  int ne = X509_NAME_entry_count(psubj.get());
742  if (ne >= 0) {
743  X509_NAME_ENTRY *cne = X509_NAME_delete_entry(psubj.get(), ne-1);
744  if (cne) {
745  X509_NAME_ENTRY_free(cne);
746  } else {
747  DEBUG("problems modifying subject name");
748  }
749  }
750  *xcro = 0;
751  }
752  // Create an entry with the common name
753  unsigned char sn[20] = {0};
754  sprintf((char *)sn, "%d", serial);
755  if (!X509_NAME_add_entry_by_txt(psubj.get(), (char *)"CN", MBSTRING_ASC,
756  sn, -1, -1, 0)) {
757  PRINT("could not add CN - (serial: "<<serial<<", sn: "<<sn<<")");
758  return -kErrPX_SetAttribute;
759  }
760  //
761  // Set the name
762  if (X509_REQ_set_subject_name(xro.get(), psubj.get()) != 1) {
763  PRINT("could not set subject name - return");
764  return -kErrPX_SetAttribute;
765  }
766  psubj = nullptr;
767  //
768  // Create the extension CertProxyInfo
769  pci.reset(PROXY_CERT_INFO_EXTENSION_new());
770  if (!pci) {
771  PRINT("could not create structure for extension - return");
772  return -kErrPX_NoResources;
773  }
774  pci->proxyPolicy->policyLanguage = OBJ_txt2obj("1.3.6.1.5.5.7.21.1", 1);
775  //
776  // Create a stack
777  esk.reset(sk_X509_EXTENSION_new_null());
778  if (!esk) {
779  PRINT("could not create stack for extensions");
780  return -kErrPX_NoResources;
781  }
782  //
783  // Get signature path depth from present proxy
784 #if OPENSSL_VERSION_NUMBER < 0x40000000L
785  X509_EXTENSION *xpiext = 0;
786 #else
787  const X509_EXTENSION *xpiext = 0;
788 #endif
789  int npiext = X509_get_ext_count(xpi);
790  int i = 0;
791  bool haskeyusage = 0;
792  int indepthlen = -1;
793  for (i = 0; i< npiext; i++) {
794  xpiext = X509_get_ext(xpi, i);
795  char s[256];
796  OBJ_obj2txt(s, sizeof(s), X509_EXTENSION_get_object(xpiext), 1);
797  // Flag key usage extension
798  if (!haskeyusage && !strcmp(s, KEY_USAGE_OID)) haskeyusage = 1;
799  // Skip subject alternative name extension
800  if (!strcmp(s, SUBJ_ALT_NAME_OID)) continue;
801  // Get signature path depth from present proxy
802  if (!strcmp(s, gsiProxyCertInfo_OID) ||
803  !strcmp(s, gsiProxyCertInfo_OLD_OID)) {
804  const unsigned char *p = ASN1_STRING_get0_data(X509_EXTENSION_get_data(xpiext));
805  PROXY_CERT_INFO_EXTENSION *inpci = 0;
806  if (!strcmp(s, gsiProxyCertInfo_OID))
807  inpci = d2i_PROXY_CERT_INFO_EXTENSION(0, &p, ASN1_STRING_length(X509_EXTENSION_get_data(xpiext)));
808  else
809  inpci = d2i_PROXY_CERT_INFO_EXTENSION_OLD(0, &p, ASN1_STRING_length(X509_EXTENSION_get_data(xpiext)));
810  if (inpci &&
811  inpci->pcPathLengthConstraint)
812  indepthlen = ASN1_INTEGER_get(inpci->pcPathLengthConstraint);
813  DEBUG("IN depth length: "<<indepthlen);
814  PROXY_CERT_INFO_EXTENSION_free(inpci);
815  } else {
816  // Duplicate and add to the stack
817  X509_EXTENSION *xpiextdup = X509_EXTENSION_dup(xpiext);
818  if (sk_X509_EXTENSION_push(esk.get(), xpiextdup) == 0) {
819  PRINT("could not push the extension '"<<s<<"' in the stack");
820  X509_EXTENSION_free(xpiextdup);
821  return -kErrPX_Error;
822  }
823  // Notify what we added
824  int crit = X509_EXTENSION_get_critical(xpiextdup);
825  DEBUG("added extension '"<<s<<"', critical: " << crit);
826  }
827  // Do not free the extension: its owned by the certificate
828  xpiext = 0;
829  }
830  //
831  // Warn if the critical oen is missing
832  if (!haskeyusage) {
833  PRINT(">>> WARNING: critical extension 'Key Usage' not found in original certificate! ");
834  PRINT(">>> WARNING: this proxy may not be accepted by some parsers. ");
835  }
836  //
837  // Set the new length
838  if (indepthlen > -1) {
839  if ((pci->pcPathLengthConstraint = ASN1_INTEGER_new())) {
840  int depthlen = (indepthlen > 0) ? (indepthlen-1) : 0;
841  ASN1_INTEGER_set(pci->pcPathLengthConstraint, depthlen);
842  } else {
843  PRINT("could not set the path length contrain");
844  return -kErrPX_SetPathDepth;
845  }
846  }
847  //
848  // create extension
849  ext.reset(X509_EXTENSION_new());
850  if (!ext) {
851  PRINT("could not create extension object");
852  return -kErrPX_NoResources;
853  }
854  // Extract data in format for extension
855  int len = i2d_PROXY_CERT_INFO_EXTENSION(pci.get(), 0);
856  unsigned char *data = (unsigned char *) malloc(len);
857  if (!data) {
858  PRINT("could not allocate data field for extension");
859  return -kErrPX_NoResources;
860  }
861  unsigned char *pp = data;
862  if ((i2d_PROXY_CERT_INFO_EXTENSION(pci.get(), &pp)) <= 0) {
863  PRINT("problem converting data for extension");
864  free(data);
865  return -kErrPX_Error;
866  }
867  ASN1_OCTET_STRING *os = ASN1_OCTET_STRING_new();
868  if (!os) {
869  PRINT("could not allocate data field for extension");
870  free(data);
871  return -kErrPX_NoResources;
872  }
873  if (ASN1_OCTET_STRING_set(os, data, len) == 0) {
874  PRINT("could not allocate data field for extension");
875  ASN1_STRING_free(os);
876  free(data);
877  return -kErrPX_NoResources;
878  }
879  free(data);
880  if (X509_EXTENSION_set_data(ext.get(), os) == 0) {
881  PRINT("could not allocate data field for extension");
882  ASN1_STRING_free(os);
883  return -kErrPX_NoResources;
884  }
885  ASN1_STRING_free(os);
886  pci = nullptr;
887 
888  // Set extension name.
889  ASN1_OBJECT *obj = OBJ_txt2obj(gsiProxyCertInfo_OID, 1);
890  if (!obj || X509_EXTENSION_set_object(ext.get(), obj) != 1) {
891  PRINT("could not set extension name");
892  ASN1_OBJECT_free(obj);
893  return -kErrPX_SetAttribute;
894  }
895  ASN1_OBJECT_free(obj);
896  obj = 0;
897 
898  // flag as critical
899  if (X509_EXTENSION_set_critical(ext.get(), 1) != 1) {
900  PRINT("could not set extension critical flag");
901  return -kErrPX_SetAttribute;
902  }
903  if (sk_X509_EXTENSION_push(esk.get(), ext.get()) == 0) {
904  PRINT("could not push the extension in the stack");
905  return -kErrPX_Error;
906  }
907  // ext resource now owned by esk
908  ext.release();
909 
910  // Add extensions
911  if (!(X509_REQ_add_extensions(xro.get(), esk.get()))) {
912  PRINT("problem adding extension");
913  return -kErrPX_SetAttribute;
914  }
915  //
916  // Sign the request
917  if (!(X509_REQ_sign(xro.get(), ekro.get(), EVP_sha256()))) {
918  PRINT("problems signing the request");
919  return -kErrPX_Signing;
920  }
921 
922  // Prepare output
923  *xcro = new XrdCryptosslX509Req(xro.get());
924  *kcro = new XrdCryptosslRSA(ekro.get());
925 
926  // xro, ekro resoruce now owned by *xcro and *kcro
927  xro.release();
928  ekro.release();
929 
930  // We are done
931  return 0;
932 }
933 
934 
935 //____________________________________________________________________________
937  XrdCryptoX509Req *xcri, XrdCryptoX509 **xcpo)
938 {
939  // Sign a proxy certificate request.
940  // Return 0 in case of success, < 0 otherwise
941  EPNAME("X509SignProxyReq");
942 
943  // Make sure we got the right inputs
944  if (!xcpi || !kcpi || !xcri || !xcpo) {
945  PRINT("invalid inputs");
946  return -1;
947  }
948 
949  // Make sure the certificate is not expired
950  int timeleft = xcpi->NotAfter() - (int)time(0);
951  if (timeleft < 0) {
952  PRINT("EEC certificate has expired");
953  return -kErrPX_ExpiredEEC;
954  }
955  // Point to the cerificate
956  X509 *xpi = (X509 *)(xcpi->Opaque());
957 
958  // Check key consistency
959  if (kcpi->status != XrdCryptoRSA::kComplete) {
960  PRINT("inconsistent key loaded");
961  return -kErrPX_BadEECkey;
962  }
963 
964  // These will be assigned dynamically allocated ssl structures later.
965  // They use type aliases for unique_ptr, to ease use of a smart pointer.
966  //
967  EVP_PKEY_ptr ekpi(nullptr, &EVP_PKEY_free);
968  X509_ptr xpo(nullptr, &X509_free);
969  X509_EXTENSION_ptr ext(nullptr, &X509_EXTENSION_free);
970  PROXY_CERT_INFO_EXTENSION_ptr pci(nullptr, &PROXY_CERT_INFO_EXTENSION_free);
972 
973  // Point to the cerificate
974 #if OPENSSL_VERSION_NUMBER >= 0x30000000L
975  ekpi.reset(EVP_PKEY_dup((EVP_PKEY *)(kcpi->Opaque())));
976  if (!ekpi) {
977  PRINT("could not create a EVP_PKEY * instance - return");
978  return -kErrPX_NoResources;
979  }
980 #else
981  RSA *kpi = EVP_PKEY_get0_RSA((EVP_PKEY *)(kcpi->Opaque()));
982  //
983  // Set the key into the request
984  ekpi.reset(EVP_PKEY_new());
985  if (!ekpi) {
986  PRINT("could not create a EVP_PKEY * instance - return");
987  return -kErrPX_NoResources;
988  }
989  EVP_PKEY_set1_RSA(ekpi.get(), kpi);
990 #endif
991 
992  // Get request in raw form
993  X509_REQ *xri = (X509_REQ *)(xcri->Opaque());
994 
995  // Extract subject names
996  XrdOucString psbj, rsbj;
997  XrdCryptosslNameOneLine(X509_get_subject_name(xpi), psbj);
998  XrdCryptosslNameOneLine(X509_REQ_get_subject_name(xri), rsbj);
999  if (psbj.length() <= 0 || rsbj.length() <= 0) {
1000  PRINT("names undefined");
1001  return -kErrPX_BadNames;
1002  }
1003 
1004  // Check the subject name: the new proxy one must be in the form
1005  // '<issuer subject> + /CN=<serial>'
1006  XrdOucString neecp(psbj);
1007  XrdOucString neecr(rsbj,0,rsbj.rfind("/CN=")-1);
1008  if (neecr.length() <= 0 || neecr.length() <= 0 || neecp != neecr) {
1009  if (xcri->Version() <= 10100) {
1010  // Support previous format
1011  neecp.erase(psbj.rfind("/CN="));
1012  if (neecr.length() <= 0 || neecr.length() <= 0 || neecp != neecr) {
1013  PRINT("Request subject not in the form '<EEC subject> + /CN=<serial>'");
1014  PRINT(" Versn: "<<xcri->Version());
1015  PRINT(" Proxy: "<<neecp);
1016  PRINT(" SubRq: "<<neecr);
1017  return -kErrPX_BadNames;
1018  }
1019  } else {
1020  PRINT("Request subject not in the form '<issuer subject> + /CN=<serial>'");
1021  PRINT(" Versn: "<<xcri->Version());
1022  PRINT(" Proxy: "<<neecp);
1023  PRINT(" SubRq: "<<neecr);
1024  return -kErrPX_BadNames;
1025  }
1026  }
1027 
1028  // Extract serial number
1029  XrdOucString sserial(rsbj,rsbj.rfind("/CN=")+4);
1030  unsigned int serial = (unsigned int)(strtol(sserial.c_str(), 0, 10));
1031  //
1032  // Create new proxy cert
1033  xpo.reset(X509_new());
1034  if (!xpo) {
1035  PRINT("could not create certificate object for proxies");
1036  return -kErrPX_NoResources;
1037  }
1038 
1039  // Set version number
1040  if (X509_set_version(xpo.get(), 2L) != 1) {
1041  PRINT("could not set version");
1042  return -kErrPX_SetAttribute;
1043  }
1044 
1045  // Set serial number
1046  if (ASN1_INTEGER_set(X509_get_serialNumber(xpo.get()), serial) != 1) {
1047  PRINT("could not set serial number");
1048  return -kErrPX_SetAttribute;
1049  }
1050 
1051  // Set subject name
1052  if (X509_set_subject_name(xpo.get(), X509_REQ_get_subject_name(xri)) != 1) {
1053  PRINT("could not set subject name");
1054  return -kErrPX_SetAttribute;
1055  }
1056 
1057  // Set issuer name
1058  if (X509_set_issuer_name(xpo.get(), X509_get_subject_name(xpi)) != 1) {
1059  PRINT("could not set issuer name");
1060  return -kErrPX_SetAttribute;
1061  }
1062 
1063  // Set public key
1064  if (X509_set_pubkey(xpo.get(), X509_REQ_get_pubkey(xri)) != 1) {
1065  PRINT("could not set public key");
1066  return -kErrPX_SetAttribute;
1067  }
1068 
1069  // Set proxy validity: notBefore now
1070  if (!X509_gmtime_adj(X509_get_notBefore(xpo.get()), 0)) {
1071  PRINT("could not set notBefore");
1072  return -kErrPX_SetAttribute;
1073  }
1074 
1075  // Set proxy validity: notAfter timeleft from now
1076  if (!X509_gmtime_adj(X509_get_notAfter(xpo.get()), timeleft)) {
1077  PRINT("could not set notAfter");
1078  return -kErrPX_SetAttribute;
1079  }
1080 
1081  //
1082  // Get signature path depth from input proxy
1083 #if OPENSSL_VERSION_NUMBER < 0x40000000L
1084  X509_EXTENSION *xpiext = 0, *xriext = 0;
1085 #else
1086  const X509_EXTENSION *xpiext = 0, *xriext = 0;
1087 #endif
1088  int npiext = X509_get_ext_count(xpi);
1089  int i = 0;
1090  bool haskeyusage = 0;
1091  int indepthlen = -1;
1092  for (i = 0; i< npiext; i++) {
1093  xpiext = X509_get_ext(xpi, i);
1094  char s[256] = {0};
1095  const ASN1_OBJECT *obj = X509_EXTENSION_get_object(xpiext);
1096  if (obj)
1097  OBJ_obj2txt(s, sizeof(s), obj, 1);
1098  if (!strcmp(s, gsiProxyCertInfo_OID) ||
1099  !strcmp(s, gsiProxyCertInfo_OLD_OID)) {
1100  const unsigned char *p = ASN1_STRING_get0_data(X509_EXTENSION_get_data(xpiext));
1101  PROXY_CERT_INFO_EXTENSION *inpci = 0;
1102  if (!strcmp(s, gsiProxyCertInfo_OID))
1103  inpci = d2i_PROXY_CERT_INFO_EXTENSION(0, &p, ASN1_STRING_length(X509_EXTENSION_get_data(xpiext)));
1104  else
1105  inpci = d2i_PROXY_CERT_INFO_EXTENSION_OLD(0, &p, ASN1_STRING_length(X509_EXTENSION_get_data(xpiext)));
1106  if (inpci &&
1107  inpci->pcPathLengthConstraint)
1108  indepthlen = ASN1_INTEGER_get(inpci->pcPathLengthConstraint);
1109  DEBUG("IN depth length: "<<indepthlen);
1110  PROXY_CERT_INFO_EXTENSION_free(inpci);
1111  }
1112  // Flag key usage extension
1113  if (!haskeyusage && !strcmp(s, KEY_USAGE_OID)) haskeyusage = 1;
1114  // Fail if a subject alternative name extension is found
1115  if (!strcmp(s, SUBJ_ALT_NAME_OID)) {
1116  PRINT("subject alternative name extension not allowed! Skipping request");
1117  return -kErrPX_BadExtension;
1118  }
1119  // Attach to ProxyCertInfo extension if any
1120  if (!strcmp(s, gsiProxyCertInfo_OID) ||
1121  !strcmp(s, gsiProxyCertInfo_OLD_OID)) {
1122  if (xriext) {
1123  PRINT("more than one ProxyCertInfo extension! Skipping request");
1124  return -kErrPX_BadExtension;
1125  }
1126  xriext = xpiext;
1127  } else {
1128  // Duplicate and add to the stack
1129  X509_EXTENSION *xpiextdup = X509_EXTENSION_dup(xpiext);
1130  if (X509_add_ext(xpo.get(), xpiextdup, -1) == 0) {
1131  PRINT("could not push the extension '"<<s<<"' in the stack");
1132  X509_EXTENSION_free( xpiextdup );
1133  return -kErrPX_Error;
1134  }
1135  // Notify what we added
1136  int crit = X509_EXTENSION_get_critical(xpiextdup);
1137  DEBUG("added extension '"<<s<<"', critical: " << crit);
1138  X509_EXTENSION_free( xpiextdup );
1139  }
1140  // Do not free the extension: its owned by the certificate
1141  xpiext = 0;
1142  }
1143 
1144  //
1145  // Get signature path depth from the request
1146  xrisk.reset(X509_REQ_get_extensions(xri));
1147  //
1148  // There must be at most one extension
1149  int nriext = sk_X509_EXTENSION_num(xrisk.get());
1150  if (nriext == 0 || !haskeyusage) {
1151  PRINT("wrong extensions in request: "<< nriext<<", "<<haskeyusage);
1152  return -kErrPX_BadExtension;
1153  }
1154  //
1155  // Get the content
1156  int reqdepthlen = -1;
1157  if (xriext) {
1158  const unsigned char *p = ASN1_STRING_get0_data(X509_EXTENSION_get_data(xriext));
1159  PROXY_CERT_INFO_EXTENSION *reqpci =
1160  d2i_PROXY_CERT_INFO_EXTENSION(0, &p, ASN1_STRING_length(X509_EXTENSION_get_data(xriext)));
1161  if (reqpci &&
1162  reqpci->pcPathLengthConstraint)
1163  reqdepthlen = ASN1_INTEGER_get(reqpci->pcPathLengthConstraint);
1164  PROXY_CERT_INFO_EXTENSION_free(reqpci);
1165  }
1166  DEBUG("REQ depth length: "<<reqdepthlen);
1167 
1168  // We allow max indepthlen-1
1169  int outdepthlen = (reqdepthlen < indepthlen) ? reqdepthlen :
1170  (indepthlen - 1);
1171  //
1172  // Create the extension CertProxyInfo
1173  pci.reset(PROXY_CERT_INFO_EXTENSION_new());
1174  if (!pci) {
1175  PRINT("could not create structure for extension - return");
1176  return -kErrPX_NoResources;
1177  }
1178  pci->proxyPolicy->policyLanguage = OBJ_txt2obj("1.3.6.1.5.5.7.21.1", 1);
1179  //
1180  // Set the new length
1181  if (outdepthlen > -1) {
1182  if ((pci->pcPathLengthConstraint = ASN1_INTEGER_new())) {
1183  int depthlen = (outdepthlen > 0) ? (outdepthlen-1) : 0;
1184  ASN1_INTEGER_set(pci->pcPathLengthConstraint, depthlen);
1185  } else {
1186  PRINT("could not set the path length contrain");
1187  return -kErrPX_SetPathDepth;
1188  }
1189  }
1190  // create extension
1191  ext.reset(X509_EXTENSION_new());
1192  if (!ext) {
1193  PRINT("could not create extension object");
1194  return -kErrPX_NoResources;
1195  }
1196  // Extract data in format for extension
1197  int len = i2d_PROXY_CERT_INFO_EXTENSION(pci.get(), 0);
1198  unsigned char *data = (unsigned char *) malloc(len);
1199  if (!data) {
1200  PRINT("could not allocate data field for extension");
1201  return -kErrPX_NoResources;
1202  }
1203  unsigned char *pp = data;
1204  if ((i2d_PROXY_CERT_INFO_EXTENSION(pci.get(), &pp)) <= 0) {
1205  PRINT("problem converting data for extension");
1206  free(data);
1207  return -kErrPX_Error;
1208  }
1209  ASN1_OCTET_STRING *os = ASN1_OCTET_STRING_new();
1210  if (!os) {
1211  PRINT("could not allocate data field for extension");
1212  free(data);
1213  return -kErrPX_NoResources;
1214  }
1215  if (ASN1_OCTET_STRING_set(os, data, len) == 0) {
1216  PRINT("could not allocate data field for extension");
1217  ASN1_STRING_free(os);
1218  free(data);
1219  return -kErrPX_NoResources;
1220  }
1221  free(data);
1222  if (X509_EXTENSION_set_data(ext.get(), os) == 0) {
1223  PRINT("could not allocate data field for extension");
1224  ASN1_STRING_free(os);
1225  return -kErrPX_NoResources;
1226  }
1227  ASN1_STRING_free(os);
1228  pci = nullptr;
1229 
1230  // Set extension name.
1231  ASN1_OBJECT *obj = OBJ_txt2obj(gsiProxyCertInfo_OID, 1);
1232  if (!obj || X509_EXTENSION_set_object(ext.get(), obj) != 1) {
1233  PRINT("could not set extension name");
1234  ASN1_OBJECT_free( obj );
1235  return -kErrPX_SetAttribute;
1236  }
1237  ASN1_OBJECT_free( obj );
1238  obj = 0;
1239 
1240  // flag as critical
1241  if (X509_EXTENSION_set_critical(ext.get(), 1) != 1) {
1242  PRINT("could not set extension critical flag");
1243  return -kErrPX_SetAttribute;
1244  }
1245 
1246  // Add the extension (adds a copy of the extension)
1247  if (X509_add_ext(xpo.get(), ext.get(), -1) == 0) {
1248  PRINT("could not add extension");
1249  return -kErrPX_SetAttribute;
1250  }
1251 
1252  //
1253  // Sign the certificate
1254  if (!(X509_sign(xpo.get(), ekpi.get(), EVP_sha256()))) {
1255  PRINT("problems signing the certificate");
1256  return -kErrPX_Signing;
1257  }
1258 
1259  ekpi = nullptr;
1260  ext = nullptr;
1261 
1262  // Prepare outputs
1263  *xcpo = new XrdCryptosslX509(xpo.get());
1264 
1265  // xpo resource is now owned by the *xcpo
1266  xpo.release();
1267 
1268  // We are done
1269  return 0;
1270 }
1271 
1272 //____________________________________________________________________________
1274 {
1275  // Get VOMS attributes from the certificate, if present
1276  // Return 0 in case of success, 1 if VOMS info is not available, < 0 if any
1277  // error occurred
1278  EPNAME("X509GetVOMSAttr");
1279 
1280  int rc = -1;
1281  // Make sure we got the right inputs
1282  if (!xcpi) {
1283  PRINT("invalid inputs");
1284  return rc;
1285  }
1286 
1287  // Point to the cerificate
1288  X509 *xpi = (X509 *)(xcpi->Opaque());
1289 
1290  rc = 1;
1291  bool getvat = 0;
1292  // Go through the extensions
1293 #if OPENSSL_VERSION_NUMBER < 0x40000000L
1294  X509_EXTENSION *xpiext = 0;
1295 #else
1296  const X509_EXTENSION *xpiext = 0;
1297 #endif
1298  int npiext = X509_get_ext_count(xpi);
1299  int i = 0;
1300  for (i = 0; i< npiext; i++) {
1301  xpiext = X509_get_ext(xpi, i);
1302  char s[256];
1303  OBJ_obj2txt(s, sizeof(s), X509_EXTENSION_get_object(xpiext), 1);
1304  // Notify what we found
1305  DEBUG("found extension '"<<s<<"'");
1306  if (strcmp(s, XRDGSI_VOMS_ACSEQ_OID)) continue;
1307  // This is the VOMS extension we are interested for
1308  rc = 0;
1309  const unsigned char *pp = ASN1_STRING_get0_data(X509_EXTENSION_get_data(xpiext));
1310  long length = ASN1_STRING_length(X509_EXTENSION_get_data(xpiext));
1311  int ret = XrdCryptosslX509FillVOMS(&pp, length, getvat, vat);
1312  DEBUG("ret: " << ret << " - vat: " << vat);
1313  }
1314 
1315  // Done
1316  return rc;
1317 }
1318 
1319 //____________________________________________________________________________
1320 int XrdCryptosslX509FillVOMS(const unsigned char **pp,
1321  long length, bool &getvat, XrdOucString &vat)
1322 {
1323  // Look recursively for the VOMS attributes
1324  // Return 2 if found, 1 if to continue searching, 0 to stop
1325  EPNAME("X509FillVOMS");
1326 
1327  const unsigned char *p,*ep,*tot,*op,*opp;
1328  long len;
1329  int tag, xclass, ret = 0;
1330  int /*nl,*/ hl,j,r;
1331  ASN1_OBJECT *o = 0;
1332  ASN1_OCTET_STRING *os = 0;
1333 
1334  bool gotvat = 0;
1335  p = *pp;
1336  tot = p + length;
1337  op = p - 1;
1338  while ((p < tot) && (op < p)) {
1339  op = p;
1340  j = ASN1_get_object(&p, &len, &tag, &xclass, length);
1341 #ifdef LINT
1342  j = j;
1343 #endif
1344  if (j & 0x80) {
1345  PRINT("ERROR: error in encoding");
1346  ret = 0;
1347  goto end;
1348  }
1349  hl = (p-op);
1350  length -= hl;
1351  /* if j == 0x21 it is a constructed indefinite length object */
1352 
1353  if (j & V_ASN1_CONSTRUCTED) {
1354  ep = p + len;
1355  if (len > length) {
1356  PRINT("ERROR:CONST: length is greater than " <<length);
1357  ret=0;
1358  goto end;
1359  }
1360  if ((j == 0x21) && (len == 0)) {
1361  for (;;) {
1362  r = XrdCryptosslX509FillVOMS(&p, (long)(tot-p), getvat, vat);
1363  if (r == 0) {
1364  ret = 0;
1365  goto end;
1366  }
1367  if ((r == 2) || (p >= tot))
1368  break;
1369  }
1370  } else {
1371  while (p < ep) {
1372  r = XrdCryptosslX509FillVOMS(&p, (long)len, getvat, vat);
1373  if (r == 0) {
1374  ret = 0;
1375  goto end;
1376  }
1377  }
1378  }
1379  } else {
1380  // nl = 0;
1381  if (tag == V_ASN1_OBJECT) {
1382  opp = op;
1383  if (d2i_ASN1_OBJECT(&o, &opp, len+hl)) {
1384  BIO *mem = BIO_new(BIO_s_mem());
1385  i2a_ASN1_OBJECT(mem, o);
1386  XrdOucString objstr;
1387  BIO_GET_STRING(mem, objstr);
1388  // Looking for the right extension ...
1389  if (objstr == XRDGSI_VOMS_ATCAP_OID || objstr == "idatcap") getvat = 1;
1390  DEBUG("AOBJ:"<<objstr<< " (getvat: "<<getvat<<")");
1391  } else {
1392  PRINT("ERROR:AOBJ: BAD OBJECT");
1393  }
1394  } else if (tag == V_ASN1_OCTET_STRING) {
1395  int i, printable = 1;
1396  opp = op;
1397  os = d2i_ASN1_OCTET_STRING(0, &opp, len + hl);
1398  if (os && ASN1_STRING_length(os) > 0) {
1399  opp = ASN1_STRING_get0_data(os);
1400  // Testing whether the octet string is printable
1401  for (i=0; i < ASN1_STRING_length(os); i++) {
1402  if (( (opp[i] < ' ') && (opp[i] != '\n') &&
1403  (opp[i] != '\r') && (opp[i] != '\t')) || (opp[i] > '~')) {
1404  printable = 0;
1405  break;
1406  }
1407  }
1408  if (printable) {
1409  // Printable string: it may be what we need
1410  if (getvat) {
1411  if (vat.length() > 0) vat += ",";
1412  vat += (const char *)opp;
1413  gotvat = 1;
1414  }
1415  DEBUG("OBJS:" << (const char *)opp << " (len: " << ASN1_STRING_length(os) << ")");
1416  }
1417  }
1418  if (os) {
1419  ASN1_OCTET_STRING_free(os);
1420  os = 0;
1421  }
1422  }
1423 
1424  p += len;
1425  if ((tag == V_ASN1_EOC) && (xclass == 0)) {
1426  ret = 2; /* End of sequence */
1427  goto end;
1428  }
1429  }
1430  length -= len;
1431  }
1432  ret = 1;
1433  if (gotvat) {
1434  getvat = 0;
1435  ret = 2;
1436  }
1437 end:
1438  if (o) ASN1_OBJECT_free(o);
1439  if (os) ASN1_OCTET_STRING_free(os);
1440  *pp = p;
1441  DEBUG("ret: "<<ret<<" - getvat: "<<getvat);
1442 
1443  return ret;
1444 }
1445 
1446 //____________________________________________________________________________
1448  //
1449  // Check GSI 3 proxy info extension
1450  // Returns: 0 if found
1451  // -1 if found by invalid/not usable,
1452  // -2 if not found (likely a v2 legacy proxy)
1453 
1454  EPNAME("X509CheckProxy3");
1455 
1456  // Point to the cerificate
1457  X509 *cert = (X509 *)(xcpi->Opaque());
1458 
1459  // Are there any extension?
1460  int numext = X509_get_ext_count(cert);
1461  if (numext <= 0) {
1462  emsg = "certificate has got no extensions";
1463  return -1;
1464  }
1465  TRACE(ALL,"certificate has "<<numext<<" extensions");
1466 
1467 #if OPENSSL_VERSION_NUMBER < 0x40000000L
1468  X509_EXTENSION *ext = 0;
1469 #else
1470  const X509_EXTENSION *ext = 0;
1471 #endif
1472  PROXY_CERT_INFO_EXTENSION *pci = 0;
1473  for (int i = 0; i < numext; i++) {
1474  // Get the extension
1475 #if OPENSSL_VERSION_NUMBER < 0x40000000L
1476  X509_EXTENSION *xext = X509_get_ext(cert, i);
1477 #else
1478  const X509_EXTENSION *xext = X509_get_ext(cert, i);
1479 #endif
1480  // We are looking for gsiProxyCertInfo_OID ("1.3.6.1.5.5.7.1.14")
1481  // or gsiProxyCertInfo_OLD_OID ("1.3.6.1.4.1.3536.1.222")
1482  char s[256];
1483  OBJ_obj2txt(s, sizeof(s), X509_EXTENSION_get_object(xext), 1);
1484  DEBUG(i << ": got: "<< s);
1485  if (!strncmp(s, gsiProxyCertInfo_OID, sizeof(gsiProxyCertInfo_OID))) {
1486  if (ext == 0) {
1487  ext = xext;
1488  // Now get the extension
1489  const unsigned char *p = ASN1_STRING_get0_data(X509_EXTENSION_get_data(ext));
1490  pci = d2i_PROXY_CERT_INFO_EXTENSION(0, &p, ASN1_STRING_length(X509_EXTENSION_get_data(ext)));
1491  } else {
1492  PRINT("WARNING: multiple proxyCertInfo extensions found: taking the first");
1493  }
1494  } else if (!strncmp(s, gsiProxyCertInfo_OLD_OID, sizeof(gsiProxyCertInfo_OLD_OID))) {
1495  if (ext == 0) {
1496  ext = xext;
1497  // Now get the extension
1498  const unsigned char *p = ASN1_STRING_get0_data(X509_EXTENSION_get_data(ext));
1499  pci = d2i_PROXY_CERT_INFO_EXTENSION_OLD(0, &p, ASN1_STRING_length(X509_EXTENSION_get_data(ext)));
1500  } else {
1501  PRINT("WARNING: multiple proxyCertInfo extensions found: taking the first");
1502  }
1503  }
1504  }
1505  //
1506  // If the extension was not found it is probably a legacy (v2) proxy: signal it
1507  if (!ext) {
1508  emsg = "proxyCertInfo extension not found";
1509  return -2;
1510  }
1511  if (!pci) {
1512  emsg = "proxyCertInfo extension could not be deserialized";
1513  return -1;
1514  }
1515 
1516  // Check if there is a policy
1517  if ((pci->proxyPolicy) == 0) {
1518  emsg = "could not access policy from proxyCertInfo extension";
1519  return -1;
1520  }
1521 
1522  if ((pci->proxyPolicy->policyLanguage) == 0) {
1523  emsg = "could not access policy language from proxyCertInfo extension";
1524  return -1;
1525  }
1526 
1527  // Done
1528  return 0;
1529 }
#define DEBUG(x)
Definition: XrdBwmTrace.hh:54
#define EPNAME(x)
Definition: XrdBwmTrace.hh:56
#define XrdCryptoMinRSABits
Definition: XrdCryptoAux.hh:52
#define XrdCryptoDefRSABits
Definition: XrdCryptoAux.hh:53
#define gsiProxyCertInfo_OID
#define gsiProxyCertInfo_OLD_OID
void * XrdCryptoX509data
time_t XrdCryptosslASN1toUTC(const ASN1_TIME *tsn1)
void XrdCryptosslNameOneLine(const X509_NAME *nm, XrdOucString &s)
void XrdCryptosslSetPathLenConstraint(void *ext, int pathlen)
#define kErrPX_ProxyFile
#define kErrPX_BadExtension
int XrdCryptosslX509CheckProxy3(XrdCryptoX509 *, XrdOucString &)
#define kErrPX_SetAttribute
#define kErrPX_Signing
int XrdCryptosslX509SignProxyReq(XrdCryptoX509 *, XrdCryptoRSA *, XrdCryptoX509Req *, XrdCryptoX509 **)
#define kErrPX_BadNames
#define kErrPX_Error
bool XrdCryptosslProxyCertInfo(const void *ext, int &pathlen, bool *haspolicy=0)
#define kErrPX_NoResources
int XrdCryptosslX509CreateProxyReq(XrdCryptoX509 *, XrdCryptoX509Req **, XrdCryptoRSA **)
int XrdCryptosslX509CreateProxy(const char *, const char *, XrdProxyOpt_t *, XrdCryptogsiX509Chain *, XrdCryptoRSA **, const char *)
int XrdCryptosslX509GetVOMSAttr(XrdCryptoX509 *, XrdOucString &)
#define kErrPX_GenerateKey
#define kErrPX_SetPathDepth
#define kErrPX_ExpiredEEC
#define kErrPX_BadEECfile
#define kErrPX_BadEECkey
#define PRINT(y)
static int XrdCheckRSA(EVP_PKEY *pkey)
std::unique_ptr< EVP_PKEY, decltype(&EVP_PKEY_free)> EVP_PKEY_ptr
#define BIO_GET_STRING(b, str)
int XrdCryptosslX509FillUnknownExt(const unsigned char **pp, long length)
#define KEY_USAGE_OID
static void stackOfX509ExtensionDelete(STACK_OF(X509_EXTENSION) *ske)
#define XRDGSI_VOMS_ATCAP_OID
int XrdCryptosslX509Asn1PrintInfo(int tag, int xclass, int constructed, int indent)
int XrdCryptosslX509FillVOMS(const unsigned char **pp, long length, bool &getvat, XrdOucString &vat)
#define XRDGSI_VOMS_ACSEQ_OID
#define SUBJ_ALT_NAME_OID
std::unique_ptr< STACK_OF(X509_EXTENSION), decltype(&stackOfX509ExtensionDelete)> STACK_OF_X509_EXTENSION_ptr
std::unique_ptr< X509, decltype(&X509_free)> X509_ptr
std::unique_ptr< X509_NAME, decltype(&X509_NAME_free)> X509_NAME_ptr
std::unique_ptr< X509_EXTENSION, decltype(&X509_EXTENSION_free)> X509_EXTENSION_ptr
std::unique_ptr< PROXY_CERT_INFO_EXTENSION, decltype(&PROXY_CERT_INFO_EXTENSION_free)> PROXY_CERT_INFO_EXTENSION_ptr
std::unique_ptr< X509_REQ, decltype(&X509_REQ_free)> X509_REQ_ptr
int fclose(FILE *stream)
#define fopen(a, b)
Definition: XrdPosix.hh:54
int emsg(int rc, char *msg)
#define TRACE(act, x)
Definition: XrdTrace.hh:63
ERSAStatus status
Definition: XrdCryptoRSA.hh:58
virtual XrdCryptoRSAdata Opaque()
Definition: XrdCryptoRSA.cc:51
void PushBack(XrdCryptoX509 *c)
virtual XrdCryptoX509Reqdata Opaque()
virtual XrdCryptoX509data Opaque()
virtual bool IsValid(int when=0)
virtual time_t NotAfter()
int rfind(const char c, int start=STR_NPOS)
int length() const
static unsigned int GetUInt()
Definition: XrdSutRndm.cc:247