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