XRootD
Loading...
Searching...
No Matches
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//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
60static 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}
67using EVP_PKEY_ptr = std::unique_ptr<EVP_PKEY, decltype(&EVP_PKEY_free)>;
68using X509_ptr = std::unique_ptr<X509, decltype(&X509_free)>;
69using X509_NAME_ptr = std::unique_ptr<X509_NAME, decltype(&X509_NAME_free)>;
70using X509_REQ_ptr = std::unique_ptr<X509_REQ, decltype(&X509_REQ_free)>;
71using X509_EXTENSION_ptr = std::unique_ptr<X509_EXTENSION, decltype(&X509_EXTENSION_free)>;
72using PROXY_CERT_INFO_EXTENSION_ptr = std::unique_ptr<PROXY_CERT_INFO_EXTENSION, decltype(&PROXY_CERT_INFO_EXTENSION_free)>;
73using 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
130static 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
139static 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
155int XrdCryptosslX509Asn1PrintInfo(int tag, int xclass, int constructed, int indent);
156int XrdCryptosslX509FillUnknownExt(XRDGSI_CONST unsigned char **pp, long length);
158 long length, bool &getvat, XrdOucString &vat);
159
160//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
161// //
162// Handlers of the ProxyCertInfo extension following RFC3820 //
163// //
164//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
165
166ASN1_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
172IMPLEMENT_ASN1_ENCODE_FUNCTIONS_fname(PROXY_CERT_INFO_EXTENSION, PROXY_CERT_INFO_EXTENSION_OLD, PROXY_CERT_INFO_EXTENSION_OLD)
173
174//___________________________________________________________________________
175bool 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//___________________________________________________________________________
222void 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//____________________________________________________________________________
258int 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//____________________________________________________________________________
1281int 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 }
1398end:
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)
#define EPNAME(x)
#define XrdCryptoMinRSABits
#define XrdCryptoDefRSABits
#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
static RSA * EVP_PKEY_get0_RSA(EVP_PKEY *pkey)
#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:49
int emsg(int rc, char *msg)
#define TRACE(act, x)
Definition XrdTrace.hh:63
ERSAStatus status
virtual XrdCryptoRSAdata Opaque()
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()