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  unsigned char *p = X509_EXTENSION_get_data(ext)->data;
169  PROXY_CERT_INFO_EXTENSION *pci = 0;
170  if (!strcmp(s, gsiProxyCertInfo_OID))
171  pci = d2i_PROXY_CERT_INFO_EXTENSION(0, (const unsigned char **)(&p), X509_EXTENSION_get_data(ext)->length);
172  else if (!strcmp(s, gsiProxyCertInfo_OLD_OID))
173  pci = d2i_PROXY_CERT_INFO_EXTENSION_OLD(0, (const unsigned char **)(&p), X509_EXTENSION_get_data(ext)->length);
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  unsigned char *p = X509_EXTENSION_get_data(ext)->data;
212  PROXY_CERT_INFO_EXTENSION *pci = 0;
213  if (!strcmp(s, gsiProxyCertInfo_OID))
214  pci = d2i_PROXY_CERT_INFO_EXTENSION(0, (const unsigned char **)(&p), X509_EXTENSION_get_data(ext)->length);
215  else if (!strcmp(s, gsiProxyCertInfo_OLD_OID))
216  pci = d2i_PROXY_CERT_INFO_EXTENSION_OLD(0, (const unsigned char **)(&p), X509_EXTENSION_get_data(ext)->length);
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  X509_EXTENSION_get_data(ext)->length = i2d_PROXY_CERT_INFO_EXTENSION(pci, 0);
423  if (!(X509_EXTENSION_get_data(ext)->data = (unsigned char *)malloc(X509_EXTENSION_get_data(ext)->length+1))) {
424  PRINT("could not allocate data field for extension");
425  return -kErrPX_NoResources;
426  }
427  unsigned char *pp = X509_EXTENSION_get_data(ext)->data;
428  if ((i2d_PROXY_CERT_INFO_EXTENSION(pci, &pp)) <= 0) {
429  PRINT("problem converting data for extension");
430  return -kErrPX_Error;
431  }
432  // Create a stack
433  STACK_OF(X509_EXTENSION) *esk = sk_X509_EXTENSION_new_null();
434  if (!esk) {
435  PRINT("could not create stack for extensions");
436  return -kErrPX_NoResources;
437  }
438  //
439  // Now we add the new extension
440  if (sk_X509_EXTENSION_push(esk, ext) == 0) {
441  PRINT("could not push the extension in the stack");
442  return -kErrPX_Error;
443  }
444  // Add extension
445  if (!(X509_REQ_add_extensions(preq, esk))) {
446  PRINT("problem adding extension");
447  return -kErrPX_SetAttribute;
448  }
449  //
450  // Sign the request
451  if (!(X509_REQ_sign(preq, ekPX, EVP_sha256()))) {
452  PRINT("problems signing the request");
453  return -kErrPX_Signing;
454  }
455  //
456  // Create new proxy cert
457  X509 *xPX = X509_new();
458  if (!xPX) {
459  PRINT("could not create certificate object for proxies");
460  return -kErrPX_NoResources;
461  }
462 
463  // Set version number
464  if (X509_set_version(xPX, 2L) != 1) {
465  PRINT("could not set version");
466  return -kErrPX_SetAttribute;
467  }
468 
469  // Set serial number
470  if (ASN1_INTEGER_set(X509_get_serialNumber(xPX), serial) != 1) {
471  PRINT("could not set serial number");
472  return -kErrPX_SetAttribute;
473  }
474 
475  // Set subject name
476  if (X509_set_subject_name(xPX, psubj) != 1) {
477  PRINT("could not set subject name");
478  return -kErrPX_SetAttribute;
479  }
480  X509_NAME_free(psubj);
481 
482  // Set issuer name
483  if (X509_set_issuer_name(xPX, X509_get_subject_name(xEEC)) != 1) {
484  PRINT("could not set issuer name");
485  return -kErrPX_SetAttribute;
486  }
487 
488  // Set public key
489  if (X509_set_pubkey(xPX, ekPX) != 1) {
490  PRINT("could not set issuer name");
491  return -kErrPX_SetAttribute;
492  }
493 
494  // Set proxy validity: notBefore now
495  if (!X509_gmtime_adj(X509_get_notBefore(xPX), 0)) {
496  PRINT("could not set notBefore");
497  return -kErrPX_SetAttribute;
498  }
499 
500  // Set proxy validity: notAfter expire_secs from now
501  if (!X509_gmtime_adj(X509_get_notAfter(xPX), valid)) {
502  PRINT("could not set notAfter");
503  return -kErrPX_SetAttribute;
504  }
505 
506  // First duplicate the extensions of the EE certificate
507  X509_EXTENSION *xEECext = 0;
508  int nEECext = X509_get_ext_count(xEEC);
509  DEBUG("number of extensions found in the original certificate: "<< nEECext);
510  int i = 0;
511  bool haskeyusage = 0;
512  for (i = 0; i< nEECext; i++) {
513  xEECext = X509_get_ext(xEEC, i);
514  char s[256];
515  OBJ_obj2txt(s, sizeof(s), X509_EXTENSION_get_object(xEECext), 1);
516  // Flag key usage extension
517  if (!haskeyusage && !strcmp(s, KEY_USAGE_OID)) haskeyusage = 1;
518  // Skip subject alternative name extension
519  if (!strcmp(s, SUBJ_ALT_NAME_OID)) continue;
520  // Duplicate and add to the stack
521  X509_EXTENSION *xEECextdup = X509_EXTENSION_dup(xEECext);
522  if (X509_add_ext(xPX, xEECextdup, -1) == 0) {
523  PRINT("could not push the extension '"<<s<<"' in the stack");
524  return -kErrPX_Error;
525  }
526  // Notify what we added
527  int crit = X509_EXTENSION_get_critical(xEECextdup);
528  DEBUG("added extension '"<<s<<"', critical: " << crit);
529  }
530 
531  // Warn if the critical oen is missing
532  if (!haskeyusage) {
533  PRINT(">>> WARNING: critical extension 'Key Usage' not found in original certificate! ");
534  PRINT(">>> WARNING: this proxy may not be accepted by some parsers. ");
535  }
536 
537  // Add the extension
538  if (X509_add_ext(xPX, ext, -1) != 1) {
539  PRINT("could not add extension");
540  return -kErrPX_SetAttribute;
541  }
542 
543  //
544  // Sign the certificate
545  if (!(X509_sign(xPX, ekEEC, EVP_sha256()))) {
546  PRINT("problems signing the certificate");
547  return -kErrPX_Signing;
548  }
549 
550  // Fill outputs
551  XrdCryptoX509 *xcPX = new XrdCryptosslX509(xPX);
552  if (!xcPX) {
553  PRINT("could not create container for proxy certificate");
554  return -kErrPX_NoResources;
555  }
556  // We need the full key
557  ((XrdCryptosslX509 *)xcPX)->SetPKI((XrdCryptoX509data)ekPX);
558  xp->PushBack(xcPX);
559  XrdCryptoX509 *xcEEC = new XrdCryptosslX509(xEEC);
560  if (!xcEEC) {
561  PRINT("could not create container for EEC certificate");
562  return -kErrPX_NoResources;
563  }
564  xp->PushBack(xcEEC);
565  *kp = new XrdCryptosslRSA(ekPX);
566  if (!(*kp)) {
567  PRINT("could not creatr out PKI");
568  return -kErrPX_NoResources;
569  }
570 
571  //
572  // Write to a file if requested
573  int rc = 0;
574  if (fnp) {
575  // Open the file in write mode
576  FILE *fp = fopen(fnp,"w");
577  int ifp = -1;
578  if (!fp) {
579  PRINT("cannot open file to save the proxy certificate (file: "<<fnp<<")");
580  rc = -kErrPX_ProxyFile;
581  }
582  else if ( (ifp = fileno(fp)) == -1) {
583  PRINT("got invalid file descriptor for the proxy certificate (file: "<<
584  fnp<<")");
585  fclose(fp);
586  rc = -kErrPX_ProxyFile;
587  }
588  // Set permissions to 0600
589  else if (fchmod(ifp, 0600) == -1) {
590  PRINT("cannot set permissions on file: "<<fnp<<" (errno: "<<errno<<")");
591  fclose(fp);
592  rc = -kErrPX_ProxyFile;
593  }
594  else if (!rc && PEM_write_X509(fp, xPX) != 1) {
595  PRINT("error while writing proxy certificate");
596  fclose(fp);
597  rc = -kErrPX_ProxyFile;
598  }
599  else if (!rc && PEM_write_PrivateKey(fp, ekPX, 0, 0, 0, 0, 0) != 1) {
600  PRINT("error while writing proxy private key");
601  fclose(fp);
602  rc = -kErrPX_ProxyFile;
603  }
604  else if (!rc && PEM_write_X509(fp, xEEC) != 1) {
605  PRINT("error while writing EEC certificate");
606  fclose(fp);
607  rc = -kErrPX_ProxyFile;
608  }
609  else
610  fclose(fp);
611  // Change
612  }
613 
614  // Cleanup
615  EVP_PKEY_free(ekEEC);
616  X509_REQ_free(preq);
617  sk_X509_EXTENSION_free(esk);
618 
619  // We are done
620  return rc;
621 }
622 
623 //____________________________________________________________________________
625  XrdCryptoX509Req **xcro, XrdCryptoRSA **kcro)
626 {
627  // Create a proxy certificate request following the GSI specification
628  // (RFC 3820) for the proxy certificate 'xpi'.
629  // The proxy certificate is returned in 'xpo' and its full RSA key in 'kpo'.
630  // Policy fields in the CertProxyExtension not yet included.
631  // Return 0 in case of success, < 0 otherwise
632  EPNAME("X509CreateProxyReq");
633 
634  // Make sure we got an proxy certificate as input
635  if (!xcpi || !(xcpi->Opaque())) {
636  PRINT("input proxy certificate not specified");
637  return -1;
638  }
639 
640  // Point to the cerificate
641  X509 *xpi = (X509 *)(xcpi->Opaque());
642 
643  // Make sure the certificate is not expired
644  if (!(xcpi->IsValid())) {
645  PRINT("EEC certificate has expired");
646  return -kErrPX_ExpiredEEC;
647  }
648 
649  // These will be assigned dynamically allocated ssl structures later.
650  // They use type aliases for unique_ptr, to ease use of a smart pointer.
651  //
652  EVP_PKEY_ptr ekro(nullptr, &EVP_PKEY_free);
653  X509_EXTENSION_ptr ext(nullptr, &X509_EXTENSION_free);
654  X509_NAME_ptr psubj(nullptr, &X509_NAME_free);
655  X509_REQ_ptr xro(nullptr, &X509_REQ_free);
656  PROXY_CERT_INFO_EXTENSION_ptr pci(nullptr, &PROXY_CERT_INFO_EXTENSION_free);
658 
659  //
660  // Create a new request
661  xro.reset(X509_REQ_new());
662  if (!xro) {
663  PRINT("cannot to create cert request");
664  return -kErrPX_NoResources;
665  }
666  //
667  // Use same num of bits as the signing certificate,
668  // but no less than the minimum RSA bits (2048)
669  ekro.reset(X509_get_pubkey(xpi));
670  int bits = EVP_PKEY_bits(ekro.get());
671  ekro = nullptr;
672 
673  bits = (bits < XrdCryptoMinRSABits) ? XrdCryptoDefRSABits : bits;
674  //
675  // Create the new PKI for the proxy (exponent 65537)
676  BIGNUM *e = BN_new();
677  if (!e) {
678  PRINT("proxy key could not be generated - return");
679  return -kErrPX_GenerateKey;
680  }
681  BN_set_word(e, 0x10001);
682  EVP_PKEY_CTX *pkctx = EVP_PKEY_CTX_new_id(EVP_PKEY_RSA, 0);
683  EVP_PKEY_keygen_init(pkctx);
684  EVP_PKEY_CTX_set_rsa_keygen_bits(pkctx, bits);
685 #if OPENSSL_VERSION_NUMBER >= 0x30000000L
686  EVP_PKEY_CTX_set1_rsa_keygen_pubexp(pkctx, e);
687  BN_free(e);
688 #else
689  EVP_PKEY_CTX_set_rsa_keygen_pubexp(pkctx, e);
690 #endif
691  {
692  EVP_PKEY *tmppk = nullptr;
693  EVP_PKEY_keygen(pkctx, &tmppk);
694  ekro.reset(tmppk);
695  }
696  EVP_PKEY_CTX_free(pkctx);
697  //
698  // Set the key into the request
699  if (!ekro) {
700  PRINT("proxy key could not be generated - return");
701  return -kErrPX_GenerateKey;
702  }
703  X509_REQ_set_pubkey(xro.get(), ekro.get());
704  //
705  // Generate a serial number. Specification says that this *should*
706  // unique, so we just draw an unsigned random integer
707  unsigned int serial = XrdSutRndm::GetUInt();
708  //
709  // The subject name is the certificate subject + /CN=<rand_uint>
710  // with <rand_uint> is a random unsigned int used also as serial
711  // number.
712  // Duplicate user subject name
713  psubj.reset(X509_NAME_dup(X509_get_subject_name(xpi)));
714  if (xcro && *xcro && *((int *)(*xcro)) <= 10100) {
715  // Delete existing proxy CN addition; for backward compatibility
716  int ne = X509_NAME_entry_count(psubj.get());
717  if (ne >= 0) {
718  X509_NAME_ENTRY *cne = X509_NAME_delete_entry(psubj.get(), ne-1);
719  if (cne) {
720  X509_NAME_ENTRY_free(cne);
721  } else {
722  DEBUG("problems modifying subject name");
723  }
724  }
725  *xcro = 0;
726  }
727  // Create an entry with the common name
728  unsigned char sn[20] = {0};
729  sprintf((char *)sn, "%d", serial);
730  if (!X509_NAME_add_entry_by_txt(psubj.get(), (char *)"CN", MBSTRING_ASC,
731  sn, -1, -1, 0)) {
732  PRINT("could not add CN - (serial: "<<serial<<", sn: "<<sn<<")");
733  return -kErrPX_SetAttribute;
734  }
735  //
736  // Set the name
737  if (X509_REQ_set_subject_name(xro.get(), psubj.get()) != 1) {
738  PRINT("could not set subject name - return");
739  return -kErrPX_SetAttribute;
740  }
741  psubj = nullptr;
742  //
743  // Create the extension CertProxyInfo
744  pci.reset(PROXY_CERT_INFO_EXTENSION_new());
745  if (!pci) {
746  PRINT("could not create structure for extension - return");
747  return -kErrPX_NoResources;
748  }
749  pci->proxyPolicy->policyLanguage = OBJ_txt2obj("1.3.6.1.5.5.7.21.1", 1);
750  //
751  // Create a stack
752  esk.reset(sk_X509_EXTENSION_new_null());
753  if (!esk) {
754  PRINT("could not create stack for extensions");
755  return -kErrPX_NoResources;
756  }
757  //
758  // Get signature path depth from present proxy
759  X509_EXTENSION *xpiext = 0;
760  int npiext = X509_get_ext_count(xpi);
761  int i = 0;
762  bool haskeyusage = 0;
763  int indepthlen = -1;
764  for (i = 0; i< npiext; i++) {
765  xpiext = X509_get_ext(xpi, i);
766  char s[256];
767  OBJ_obj2txt(s, sizeof(s), X509_EXTENSION_get_object(xpiext), 1);
768  // Flag key usage extension
769  if (!haskeyusage && !strcmp(s, KEY_USAGE_OID)) haskeyusage = 1;
770  // Skip subject alternative name extension
771  if (!strcmp(s, SUBJ_ALT_NAME_OID)) continue;
772  // Get signature path depth from present proxy
773  if (!strcmp(s, gsiProxyCertInfo_OID) ||
774  !strcmp(s, gsiProxyCertInfo_OLD_OID)) {
775  unsigned char *p = X509_EXTENSION_get_data(xpiext)->data;
776  PROXY_CERT_INFO_EXTENSION *inpci = 0;
777  if (!strcmp(s, gsiProxyCertInfo_OID))
778  inpci = d2i_PROXY_CERT_INFO_EXTENSION(0, (const unsigned char **)(&p), X509_EXTENSION_get_data(xpiext)->length);
779  else
780  inpci = d2i_PROXY_CERT_INFO_EXTENSION_OLD(0, (const unsigned char **)(&p), X509_EXTENSION_get_data(xpiext)->length);
781  if (inpci &&
782  inpci->pcPathLengthConstraint)
783  indepthlen = ASN1_INTEGER_get(inpci->pcPathLengthConstraint);
784  DEBUG("IN depth length: "<<indepthlen);
785  PROXY_CERT_INFO_EXTENSION_free(inpci);
786  } else {
787  // Duplicate and add to the stack
788  X509_EXTENSION *xpiextdup = X509_EXTENSION_dup(xpiext);
789  if (sk_X509_EXTENSION_push(esk.get(), xpiextdup) == 0) {
790  PRINT("could not push the extension '"<<s<<"' in the stack");
791  X509_EXTENSION_free(xpiextdup);
792  return -kErrPX_Error;
793  }
794  // Notify what we added
795  int crit = X509_EXTENSION_get_critical(xpiextdup);
796  DEBUG("added extension '"<<s<<"', critical: " << crit);
797  }
798  // Do not free the extension: its owned by the certificate
799  xpiext = 0;
800  }
801  //
802  // Warn if the critical oen is missing
803  if (!haskeyusage) {
804  PRINT(">>> WARNING: critical extension 'Key Usage' not found in original certificate! ");
805  PRINT(">>> WARNING: this proxy may not be accepted by some parsers. ");
806  }
807  //
808  // Set the new length
809  if (indepthlen > -1) {
810  if ((pci->pcPathLengthConstraint = ASN1_INTEGER_new())) {
811  int depthlen = (indepthlen > 0) ? (indepthlen-1) : 0;
812  ASN1_INTEGER_set(pci->pcPathLengthConstraint, depthlen);
813  } else {
814  PRINT("could not set the path length contrain");
815  return -kErrPX_SetPathDepth;
816  }
817  }
818  //
819  // create extension
820  ext.reset(X509_EXTENSION_new());
821  if (!ext) {
822  PRINT("could not create extension object");
823  return -kErrPX_NoResources;
824  }
825  // Extract data in format for extension
826  X509_EXTENSION_get_data(ext.get())->length = i2d_PROXY_CERT_INFO_EXTENSION(pci.get(), 0);
827  if (!(X509_EXTENSION_get_data(ext.get())->data = (unsigned char *)malloc(X509_EXTENSION_get_data(ext.get())->length+1))) {
828  PRINT("could not allocate data field for extension");
829  return -kErrPX_NoResources;
830  }
831  unsigned char *pp = X509_EXTENSION_get_data(ext.get())->data;
832  if ((i2d_PROXY_CERT_INFO_EXTENSION(pci.get(), &pp)) <= 0) {
833  PRINT("problem converting data for extension");
834  return -kErrPX_Error;
835  }
836  pci = nullptr;
837 
838  // Set extension name.
839  ASN1_OBJECT *obj = OBJ_txt2obj(gsiProxyCertInfo_OID, 1);
840  if (!obj || X509_EXTENSION_set_object(ext.get(), obj) != 1) {
841  PRINT("could not set extension name");
842  ASN1_OBJECT_free(obj);
843  return -kErrPX_SetAttribute;
844  }
845  ASN1_OBJECT_free(obj);
846  obj = 0;
847 
848  // flag as critical
849  if (X509_EXTENSION_set_critical(ext.get(), 1) != 1) {
850  PRINT("could not set extension critical flag");
851  return -kErrPX_SetAttribute;
852  }
853  if (sk_X509_EXTENSION_push(esk.get(), ext.get()) == 0) {
854  PRINT("could not push the extension in the stack");
855  return -kErrPX_Error;
856  }
857  // ext resource now owned by esk
858  ext.release();
859 
860  // Add extensions
861  if (!(X509_REQ_add_extensions(xro.get(), esk.get()))) {
862  PRINT("problem adding extension");
863  return -kErrPX_SetAttribute;
864  }
865  //
866  // Sign the request
867  if (!(X509_REQ_sign(xro.get(), ekro.get(), EVP_sha256()))) {
868  PRINT("problems signing the request");
869  return -kErrPX_Signing;
870  }
871 
872  // Prepare output
873  *xcro = new XrdCryptosslX509Req(xro.get());
874  *kcro = new XrdCryptosslRSA(ekro.get());
875 
876  // xro, ekro resoruce now owned by *xcro and *kcro
877  xro.release();
878  ekro.release();
879 
880  // We are done
881  return 0;
882 }
883 
884 
885 //____________________________________________________________________________
887  XrdCryptoX509Req *xcri, XrdCryptoX509 **xcpo)
888 {
889  // Sign a proxy certificate request.
890  // Return 0 in case of success, < 0 otherwise
891  EPNAME("X509SignProxyReq");
892 
893  // Make sure we got the right inputs
894  if (!xcpi || !kcpi || !xcri || !xcpo) {
895  PRINT("invalid inputs");
896  return -1;
897  }
898 
899  // Make sure the certificate is not expired
900  int timeleft = xcpi->NotAfter() - (int)time(0);
901  if (timeleft < 0) {
902  PRINT("EEC certificate has expired");
903  return -kErrPX_ExpiredEEC;
904  }
905  // Point to the cerificate
906  X509 *xpi = (X509 *)(xcpi->Opaque());
907 
908  // Check key consistency
909  if (kcpi->status != XrdCryptoRSA::kComplete) {
910  PRINT("inconsistent key loaded");
911  return -kErrPX_BadEECkey;
912  }
913 
914  // These will be assigned dynamically allocated ssl structures later.
915  // They use type aliases for unique_ptr, to ease use of a smart pointer.
916  //
917  EVP_PKEY_ptr ekpi(nullptr, &EVP_PKEY_free);
918  X509_ptr xpo(nullptr, &X509_free);
919  X509_EXTENSION_ptr ext(nullptr, &X509_EXTENSION_free);
920  PROXY_CERT_INFO_EXTENSION_ptr pci(nullptr, &PROXY_CERT_INFO_EXTENSION_free);
922 
923  // Point to the cerificate
924 #if OPENSSL_VERSION_NUMBER >= 0x30000000L
925  ekpi.reset(EVP_PKEY_dup((EVP_PKEY *)(kcpi->Opaque())));
926  if (!ekpi) {
927  PRINT("could not create a EVP_PKEY * instance - return");
928  return -kErrPX_NoResources;
929  }
930 #else
931  RSA *kpi = EVP_PKEY_get0_RSA((EVP_PKEY *)(kcpi->Opaque()));
932  //
933  // Set the key into the request
934  ekpi.reset(EVP_PKEY_new());
935  if (!ekpi) {
936  PRINT("could not create a EVP_PKEY * instance - return");
937  return -kErrPX_NoResources;
938  }
939  EVP_PKEY_set1_RSA(ekpi.get(), kpi);
940 #endif
941 
942  // Get request in raw form
943  X509_REQ *xri = (X509_REQ *)(xcri->Opaque());
944 
945  // Extract subject names
946  XrdOucString psbj, rsbj;
947  XrdCryptosslNameOneLine(X509_get_subject_name(xpi), psbj);
948  XrdCryptosslNameOneLine(X509_REQ_get_subject_name(xri), rsbj);
949  if (psbj.length() <= 0 || rsbj.length() <= 0) {
950  PRINT("names undefined");
951  return -kErrPX_BadNames;
952  }
953 
954  // Check the subject name: the new proxy one must be in the form
955  // '<issuer subject> + /CN=<serial>'
956  XrdOucString neecp(psbj);
957  XrdOucString neecr(rsbj,0,rsbj.rfind("/CN=")-1);
958  if (neecr.length() <= 0 || neecr.length() <= 0 || neecp != neecr) {
959  if (xcri->Version() <= 10100) {
960  // Support previous format
961  neecp.erase(psbj.rfind("/CN="));
962  if (neecr.length() <= 0 || neecr.length() <= 0 || neecp != neecr) {
963  PRINT("Request subject not in the form '<EEC subject> + /CN=<serial>'");
964  PRINT(" Versn: "<<xcri->Version());
965  PRINT(" Proxy: "<<neecp);
966  PRINT(" SubRq: "<<neecr);
967  return -kErrPX_BadNames;
968  }
969  } else {
970  PRINT("Request subject not in the form '<issuer subject> + /CN=<serial>'");
971  PRINT(" Versn: "<<xcri->Version());
972  PRINT(" Proxy: "<<neecp);
973  PRINT(" SubRq: "<<neecr);
974  return -kErrPX_BadNames;
975  }
976  }
977 
978  // Extract serial number
979  XrdOucString sserial(rsbj,rsbj.rfind("/CN=")+4);
980  unsigned int serial = (unsigned int)(strtol(sserial.c_str(), 0, 10));
981  //
982  // Create new proxy cert
983  xpo.reset(X509_new());
984  if (!xpo) {
985  PRINT("could not create certificate object for proxies");
986  return -kErrPX_NoResources;
987  }
988 
989  // Set version number
990  if (X509_set_version(xpo.get(), 2L) != 1) {
991  PRINT("could not set version");
992  return -kErrPX_SetAttribute;
993  }
994 
995  // Set serial number
996  if (ASN1_INTEGER_set(X509_get_serialNumber(xpo.get()), serial) != 1) {
997  PRINT("could not set serial number");
998  return -kErrPX_SetAttribute;
999  }
1000 
1001  // Set subject name
1002  if (X509_set_subject_name(xpo.get(), X509_REQ_get_subject_name(xri)) != 1) {
1003  PRINT("could not set subject name");
1004  return -kErrPX_SetAttribute;
1005  }
1006 
1007  // Set issuer name
1008  if (X509_set_issuer_name(xpo.get(), X509_get_subject_name(xpi)) != 1) {
1009  PRINT("could not set issuer name");
1010  return -kErrPX_SetAttribute;
1011  }
1012 
1013  // Set public key
1014  if (X509_set_pubkey(xpo.get(), X509_REQ_get_pubkey(xri)) != 1) {
1015  PRINT("could not set public key");
1016  return -kErrPX_SetAttribute;
1017  }
1018 
1019  // Set proxy validity: notBefore now
1020  if (!X509_gmtime_adj(X509_get_notBefore(xpo.get()), 0)) {
1021  PRINT("could not set notBefore");
1022  return -kErrPX_SetAttribute;
1023  }
1024 
1025  // Set proxy validity: notAfter timeleft from now
1026  if (!X509_gmtime_adj(X509_get_notAfter(xpo.get()), timeleft)) {
1027  PRINT("could not set notAfter");
1028  return -kErrPX_SetAttribute;
1029  }
1030 
1031  //
1032  // Get signature path depth from input proxy
1033  X509_EXTENSION *xpiext = 0, *xriext = 0;
1034  int npiext = X509_get_ext_count(xpi);
1035  int i = 0;
1036  bool haskeyusage = 0;
1037  int indepthlen = -1;
1038  for (i = 0; i< npiext; i++) {
1039  xpiext = X509_get_ext(xpi, i);
1040  char s[256] = {0};
1041  ASN1_OBJECT *obj = X509_EXTENSION_get_object(xpiext);
1042  if (obj)
1043  OBJ_obj2txt(s, sizeof(s), obj, 1);
1044  if (!strcmp(s, gsiProxyCertInfo_OID) ||
1045  !strcmp(s, gsiProxyCertInfo_OLD_OID)) {
1046  unsigned char *p = X509_EXTENSION_get_data(xpiext)->data;
1047  PROXY_CERT_INFO_EXTENSION *inpci = 0;
1048  if (!strcmp(s, gsiProxyCertInfo_OID))
1049  inpci = d2i_PROXY_CERT_INFO_EXTENSION(0, (const unsigned char **)(&p), X509_EXTENSION_get_data(xpiext)->length);
1050  else
1051  inpci = d2i_PROXY_CERT_INFO_EXTENSION_OLD(0, (const unsigned char **)(&p), X509_EXTENSION_get_data(xpiext)->length);
1052  if (inpci &&
1053  inpci->pcPathLengthConstraint)
1054  indepthlen = ASN1_INTEGER_get(inpci->pcPathLengthConstraint);
1055  DEBUG("IN depth length: "<<indepthlen);
1056  PROXY_CERT_INFO_EXTENSION_free(inpci);
1057  }
1058  // Flag key usage extension
1059  if (!haskeyusage && !strcmp(s, KEY_USAGE_OID)) haskeyusage = 1;
1060  // Fail if a subject alternative name extension is found
1061  if (!strcmp(s, SUBJ_ALT_NAME_OID)) {
1062  PRINT("subject alternative name extension not allowed! Skipping request");
1063  return -kErrPX_BadExtension;
1064  }
1065  // Attach to ProxyCertInfo extension if any
1066  if (!strcmp(s, gsiProxyCertInfo_OID) ||
1067  !strcmp(s, gsiProxyCertInfo_OLD_OID)) {
1068  if (xriext) {
1069  PRINT("more than one ProxyCertInfo extension! Skipping request");
1070  return -kErrPX_BadExtension;
1071  }
1072  xriext = xpiext;
1073  } else {
1074  // Duplicate and add to the stack
1075  X509_EXTENSION *xpiextdup = X509_EXTENSION_dup(xpiext);
1076  if (X509_add_ext(xpo.get(), xpiextdup, -1) == 0) {
1077  PRINT("could not push the extension '"<<s<<"' in the stack");
1078  X509_EXTENSION_free( xpiextdup );
1079  return -kErrPX_Error;
1080  }
1081  // Notify what we added
1082  int crit = X509_EXTENSION_get_critical(xpiextdup);
1083  DEBUG("added extension '"<<s<<"', critical: " << crit);
1084  X509_EXTENSION_free( xpiextdup );
1085  }
1086  // Do not free the extension: its owned by the certificate
1087  xpiext = 0;
1088  }
1089 
1090  //
1091  // Get signature path depth from the request
1092  xrisk.reset(X509_REQ_get_extensions(xri));
1093  //
1094  // There must be at most one extension
1095  int nriext = sk_X509_EXTENSION_num(xrisk.get());
1096  if (nriext == 0 || !haskeyusage) {
1097  PRINT("wrong extensions in request: "<< nriext<<", "<<haskeyusage);
1098  return -kErrPX_BadExtension;
1099  }
1100  //
1101  // Get the content
1102  int reqdepthlen = -1;
1103  if (xriext) {
1104  unsigned char *p = X509_EXTENSION_get_data(xriext)->data;
1105  PROXY_CERT_INFO_EXTENSION *reqpci =
1106  d2i_PROXY_CERT_INFO_EXTENSION(0, (const unsigned char **)(&p), X509_EXTENSION_get_data(xriext)->length);
1107  if (reqpci &&
1108  reqpci->pcPathLengthConstraint)
1109  reqdepthlen = ASN1_INTEGER_get(reqpci->pcPathLengthConstraint);
1110  PROXY_CERT_INFO_EXTENSION_free(reqpci);
1111  }
1112  DEBUG("REQ depth length: "<<reqdepthlen);
1113 
1114  // We allow max indepthlen-1
1115  int outdepthlen = (reqdepthlen < indepthlen) ? reqdepthlen :
1116  (indepthlen - 1);
1117  //
1118  // Create the extension CertProxyInfo
1119  pci.reset(PROXY_CERT_INFO_EXTENSION_new());
1120  if (!pci) {
1121  PRINT("could not create structure for extension - return");
1122  return -kErrPX_NoResources;
1123  }
1124  pci->proxyPolicy->policyLanguage = OBJ_txt2obj("1.3.6.1.5.5.7.21.1", 1);
1125  //
1126  // Set the new length
1127  if (outdepthlen > -1) {
1128  if ((pci->pcPathLengthConstraint = ASN1_INTEGER_new())) {
1129  int depthlen = (outdepthlen > 0) ? (outdepthlen-1) : 0;
1130  ASN1_INTEGER_set(pci->pcPathLengthConstraint, depthlen);
1131  } else {
1132  PRINT("could not set the path length contrain");
1133  return -kErrPX_SetPathDepth;
1134  }
1135  }
1136  // create extension
1137  ext.reset(X509_EXTENSION_new());
1138  if (!ext) {
1139  PRINT("could not create extension object");
1140  return -kErrPX_NoResources;
1141  }
1142  // Extract data in format for extension
1143  X509_EXTENSION_get_data(ext.get())->length = i2d_PROXY_CERT_INFO_EXTENSION(pci.get(), 0);
1144  if (!(X509_EXTENSION_get_data(ext.get())->data = (unsigned char *)malloc(X509_EXTENSION_get_data(ext.get())->length+1))) {
1145  PRINT("could not allocate data field for extension");
1146  return -kErrPX_NoResources;
1147  }
1148  unsigned char *pp = X509_EXTENSION_get_data(ext.get())->data;
1149  if ((i2d_PROXY_CERT_INFO_EXTENSION(pci.get(), &pp)) <= 0) {
1150  PRINT("problem converting data for extension");
1151  return -kErrPX_Error;
1152  }
1153  pci = nullptr;
1154 
1155  // Set extension name.
1156  ASN1_OBJECT *obj = OBJ_txt2obj(gsiProxyCertInfo_OID, 1);
1157  if (!obj || X509_EXTENSION_set_object(ext.get(), obj) != 1) {
1158  PRINT("could not set extension name");
1159  ASN1_OBJECT_free( obj );
1160  return -kErrPX_SetAttribute;
1161  }
1162  ASN1_OBJECT_free( obj );
1163  obj = 0;
1164 
1165  // flag as critical
1166  if (X509_EXTENSION_set_critical(ext.get(), 1) != 1) {
1167  PRINT("could not set extension critical flag");
1168  return -kErrPX_SetAttribute;
1169  }
1170 
1171  // Add the extension (adds a copy of the extension)
1172  if (X509_add_ext(xpo.get(), ext.get(), -1) == 0) {
1173  PRINT("could not add extension");
1174  return -kErrPX_SetAttribute;
1175  }
1176 
1177  //
1178  // Sign the certificate
1179  if (!(X509_sign(xpo.get(), ekpi.get(), EVP_sha256()))) {
1180  PRINT("problems signing the certificate");
1181  return -kErrPX_Signing;
1182  }
1183 
1184  ekpi = nullptr;
1185  ext = nullptr;
1186 
1187  // Prepare outputs
1188  *xcpo = new XrdCryptosslX509(xpo.get());
1189 
1190  // xpo resource is now owned by the *xcpo
1191  xpo.release();
1192 
1193  // We are done
1194  return 0;
1195 }
1196 
1197 //____________________________________________________________________________
1199 {
1200  // Get VOMS attributes from the certificate, if present
1201  // Return 0 in case of success, 1 if VOMS info is not available, < 0 if any
1202  // error occurred
1203  EPNAME("X509GetVOMSAttr");
1204 
1205  int rc = -1;
1206  // Make sure we got the right inputs
1207  if (!xcpi) {
1208  PRINT("invalid inputs");
1209  return rc;
1210  }
1211 
1212  // Point to the cerificate
1213  X509 *xpi = (X509 *)(xcpi->Opaque());
1214 
1215  rc = 1;
1216  bool getvat = 0;
1217  // Go through the extensions
1218  X509_EXTENSION *xpiext = 0;
1219  int npiext = X509_get_ext_count(xpi);
1220  int i = 0;
1221  for (i = 0; i< npiext; i++) {
1222  xpiext = X509_get_ext(xpi, i);
1223  char s[256];
1224  OBJ_obj2txt(s, sizeof(s), X509_EXTENSION_get_object(xpiext), 1);
1225  // Notify what we found
1226  DEBUG("found extension '"<<s<<"'");
1227  if (strcmp(s, XRDGSI_VOMS_ACSEQ_OID)) continue;
1228  // This is the VOMS extension we are interested for
1229  rc = 0;
1230  const unsigned char *pp = (const unsigned char *) X509_EXTENSION_get_data(xpiext)->data;
1231  long length = X509_EXTENSION_get_data(xpiext)->length;
1232  int ret = XrdCryptosslX509FillVOMS(&pp, length, getvat, vat);
1233  DEBUG("ret: " << ret << " - vat: " << vat);
1234  }
1235 
1236  // Done
1237  return rc;
1238 }
1239 
1240 //____________________________________________________________________________
1241 int XrdCryptosslX509FillVOMS(const unsigned char **pp,
1242  long length, bool &getvat, XrdOucString &vat)
1243 {
1244  // Look recursively for the VOMS attributes
1245  // Return 2 if found, 1 if to continue searching, 0 to stop
1246  EPNAME("X509FillVOMS");
1247 
1248  const unsigned char *p,*ep,*tot,*op,*opp;
1249  long len;
1250  int tag, xclass, ret = 0;
1251  int /*nl,*/ hl,j,r;
1252  ASN1_OBJECT *o = 0;
1253  ASN1_OCTET_STRING *os = 0;
1254 
1255  bool gotvat = 0;
1256  p = *pp;
1257  tot = p + length;
1258  op = p - 1;
1259  while ((p < tot) && (op < p)) {
1260  op = p;
1261  j = ASN1_get_object(&p, &len, &tag, &xclass, length);
1262 #ifdef LINT
1263  j = j;
1264 #endif
1265  if (j & 0x80) {
1266  PRINT("ERROR: error in encoding");
1267  ret = 0;
1268  goto end;
1269  }
1270  hl = (p-op);
1271  length -= hl;
1272  /* if j == 0x21 it is a constructed indefinite length object */
1273 
1274  if (j & V_ASN1_CONSTRUCTED) {
1275  ep = p + len;
1276  if (len > length) {
1277  PRINT("ERROR:CONST: length is greater than " <<length);
1278  ret=0;
1279  goto end;
1280  }
1281  if ((j == 0x21) && (len == 0)) {
1282  for (;;) {
1283  r = XrdCryptosslX509FillVOMS(&p, (long)(tot-p), getvat, vat);
1284  if (r == 0) {
1285  ret = 0;
1286  goto end;
1287  }
1288  if ((r == 2) || (p >= tot))
1289  break;
1290  }
1291  } else {
1292  while (p < ep) {
1293  r = XrdCryptosslX509FillVOMS(&p, (long)len, getvat, vat);
1294  if (r == 0) {
1295  ret = 0;
1296  goto end;
1297  }
1298  }
1299  }
1300  } else {
1301  // nl = 0;
1302  if (tag == V_ASN1_OBJECT) {
1303  opp = op;
1304  if (d2i_ASN1_OBJECT(&o, &opp, len+hl)) {
1305  BIO *mem = BIO_new(BIO_s_mem());
1306  i2a_ASN1_OBJECT(mem, o);
1307  XrdOucString objstr;
1308  BIO_GET_STRING(mem, objstr);
1309  // Looking for the right extension ...
1310  if (objstr == XRDGSI_VOMS_ATCAP_OID || objstr == "idatcap") getvat = 1;
1311  DEBUG("AOBJ:"<<objstr<< " (getvat: "<<getvat<<")");
1312  } else {
1313  PRINT("ERROR:AOBJ: BAD OBJECT");
1314  }
1315  } else if (tag == V_ASN1_OCTET_STRING) {
1316  int i, printable = 1;
1317  opp = op;
1318  os = d2i_ASN1_OCTET_STRING(0, &opp, len + hl);
1319  if (os && os->length > 0) {
1320  opp = os->data;
1321  // Testing whether the octet string is printable
1322  for (i=0; i<os->length; i++) {
1323  if (( (opp[i] < ' ') && (opp[i] != '\n') &&
1324  (opp[i] != '\r') && (opp[i] != '\t')) || (opp[i] > '~')) {
1325  printable = 0;
1326  break;
1327  }
1328  }
1329  if (printable) {
1330  // Printable string: it may be what we need
1331  if (getvat) {
1332  if (vat.length() > 0) vat += ",";
1333  vat += (const char *)opp;
1334  gotvat = 1;
1335  }
1336  DEBUG("OBJS:" << (const char *)opp << " (len: "<<os->length<<")");
1337  }
1338  }
1339  if (os) {
1340  ASN1_OCTET_STRING_free(os);
1341  os = 0;
1342  }
1343  }
1344 
1345  p += len;
1346  if ((tag == V_ASN1_EOC) && (xclass == 0)) {
1347  ret = 2; /* End of sequence */
1348  goto end;
1349  }
1350  }
1351  length -= len;
1352  }
1353  ret = 1;
1354  if (gotvat) {
1355  getvat = 0;
1356  ret = 2;
1357  }
1358 end:
1359  if (o) ASN1_OBJECT_free(o);
1360  if (os) ASN1_OCTET_STRING_free(os);
1361  *pp = p;
1362  DEBUG("ret: "<<ret<<" - getvat: "<<getvat);
1363 
1364  return ret;
1365 }
1366 
1367 //____________________________________________________________________________
1369  //
1370  // Check GSI 3 proxy info extension
1371  // Returns: 0 if found
1372  // -1 if found by invalid/not usable,
1373  // -2 if not found (likely a v2 legacy proxy)
1374 
1375  EPNAME("X509CheckProxy3");
1376 
1377  // Point to the cerificate
1378  X509 *cert = (X509 *)(xcpi->Opaque());
1379 
1380  // Are there any extension?
1381  int numext = X509_get_ext_count(cert);
1382  if (numext <= 0) {
1383  emsg = "certificate has got no extensions";
1384  return -1;
1385  }
1386  TRACE(ALL,"certificate has "<<numext<<" extensions");
1387 
1388  X509_EXTENSION *ext = 0;
1389  PROXY_CERT_INFO_EXTENSION *pci = 0;
1390  for (int i = 0; i < numext; i++) {
1391  // Get the extension
1392  X509_EXTENSION *xext = X509_get_ext(cert, i);
1393  // We are looking for gsiProxyCertInfo_OID ("1.3.6.1.5.5.7.1.14")
1394  // or gsiProxyCertInfo_OLD_OID ("1.3.6.1.4.1.3536.1.222")
1395  char s[256];
1396  OBJ_obj2txt(s, sizeof(s), X509_EXTENSION_get_object(xext), 1);
1397  DEBUG(i << ": got: "<< s);
1398  if (!strncmp(s, gsiProxyCertInfo_OID, sizeof(gsiProxyCertInfo_OID))) {
1399  if (ext == 0) {
1400  ext = xext;
1401  // Now get the extension
1402  unsigned char *p = X509_EXTENSION_get_data(ext)->data;
1403  pci = d2i_PROXY_CERT_INFO_EXTENSION(0, (const unsigned char **)(&p), X509_EXTENSION_get_data(ext)->length);
1404  } else {
1405  PRINT("WARNING: multiple proxyCertInfo extensions found: taking the first");
1406  }
1407  } else if (!strncmp(s, gsiProxyCertInfo_OLD_OID, sizeof(gsiProxyCertInfo_OLD_OID))) {
1408  if (ext == 0) {
1409  ext = xext;
1410  // Now get the extension
1411  unsigned char *p = X509_EXTENSION_get_data(ext)->data;
1412  pci = d2i_PROXY_CERT_INFO_EXTENSION_OLD(0, (const unsigned char **)(&p), X509_EXTENSION_get_data(ext)->length);
1413  } else {
1414  PRINT("WARNING: multiple proxyCertInfo extensions found: taking the first");
1415  }
1416  }
1417  }
1418  //
1419  // If the extension was not found it is probably a legacy (v2) proxy: signal it
1420  if (!ext) {
1421  emsg = "proxyCertInfo extension not found";
1422  return -2;
1423  }
1424  if (!pci) {
1425  emsg = "proxyCertInfo extension could not be deserialized";
1426  return -1;
1427  }
1428 
1429  // Check if there is a policy
1430  if ((pci->proxyPolicy) == 0) {
1431  emsg = "could not access policy from proxyCertInfo extension";
1432  return -1;
1433  }
1434 
1435  if ((pci->proxyPolicy->policyLanguage) == 0) {
1436  emsg = "could not access policy language from proxyCertInfo extension";
1437  return -1;
1438  }
1439 
1440  // Done
1441  return 0;
1442 }
#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
#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