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