XRootD
Loading...
Searching...
No Matches
XrdCryptosslRSA.cc
Go to the documentation of this file.
1/******************************************************************************/
2/* */
3/* X r d C r y p t o S s l R S A . c c */
4/* */
5/* (c) 2004 by the Board of Trustees of the Leland Stanford, Jr., University */
6/* Produced by Gerri Ganis for CERN */
7/* */
8/* This file is part of the XRootD software suite. */
9/* */
10/* XRootD is free software: you can redistribute it and/or modify it under */
11/* the terms of the GNU Lesser General Public License as published by the */
12/* Free Software Foundation, either version 3 of the License, or (at your */
13/* option) any later version. */
14/* */
15/* XRootD is distributed in the hope that it will be useful, but WITHOUT */
16/* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or */
17/* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public */
18/* License for more details. */
19/* */
20/* You should have received a copy of the GNU Lesser General Public License */
21/* along with XRootD in a file called COPYING.LESSER (LGPL license) and file */
22/* COPYING (GPL license). If not, see <http://www.gnu.org/licenses/>. */
23/* */
24/* The copyright holder's institutional names and contributor's names may not */
25/* be used to endorse or promote products derived from this software without */
26/* specific prior written permission of the institution or contributor. */
27/******************************************************************************/
28
29/* ************************************************************************** */
30/* */
31/* OpenSSL implementation of XrdCryptoRSA */
32/* */
33/* ************************************************************************** */
34
35#include "XrdSut/XrdSutRndm.hh"
39
40#include <cstring>
41
42#include <openssl/bio.h>
43#include <openssl/err.h>
44#include <openssl/pem.h>
45#if OPENSSL_VERSION_NUMBER >= 0x30000000L
46#include <openssl/core_names.h>
47#endif
48
49static int XrdCheckRSA (EVP_PKEY *pkey) {
50 int rc;
51 EVP_PKEY_CTX *ckctx = EVP_PKEY_CTX_new(pkey, 0);
52 rc = EVP_PKEY_check(ckctx);
53 EVP_PKEY_CTX_free(ckctx);
54 return rc;
55}
56
57//_____________________________________________________________________________
59{
60 // Constructor
61 // Generate a RSA asymmetric key pair
62 // Length will be 'bits' bits (min 2048, default 2048), public
63 // exponent `pubex` (default 65537).
64 EPNAME("RSA::XrdCryptosslRSA");
65
66 publen = -1;
67 prilen = -1;
68
69 // Minimum is XrdCryptoMinRSABits
70 bits = (bits >= XrdCryptoMinRSABits) ? bits : XrdCryptoDefRSABits;
71
72 // If pubex is not odd, use default
73 if (!(exp & 1))
74 exp = XrdCryptoDefRSAExp; // 65537 (0x10001)
75
76 DEBUG("bits: "<<bits<<", exp: "<<exp);
77
78 // Try Key Generation
79 BIGNUM *e = BN_new();
80 if (!e) {
81 DEBUG("cannot allocate new exponent");
82 return;
83 }
84
85 BN_set_word(e, exp);
86
87 EVP_PKEY_CTX *pkctx = EVP_PKEY_CTX_new_id(EVP_PKEY_RSA, 0);
88 EVP_PKEY_keygen_init(pkctx);
89 EVP_PKEY_CTX_set_rsa_keygen_bits(pkctx, bits);
90#if OPENSSL_VERSION_NUMBER >= 0x30000000L
91 EVP_PKEY_CTX_set1_rsa_keygen_pubexp(pkctx, e);
92 BN_free(e);
93#else
94 EVP_PKEY_CTX_set_rsa_keygen_pubexp(pkctx, e);
95#endif
96 EVP_PKEY_keygen(pkctx, &fEVP);
97 EVP_PKEY_CTX_free(pkctx);
98
99 // Update status flag
100 if (fEVP) {
101 if (XrdCheckRSA(fEVP) == 1) {
103 DEBUG("basic length: "<<EVP_PKEY_size(fEVP)<<" bytes");
104 } else {
105 DEBUG("WARNING: generated key is invalid");
106 // Generated an invalid key: cleanup
107 EVP_PKEY_free(fEVP);
108 fEVP = 0;
109 }
110 }
111}
112
113//_____________________________________________________________________________
114XrdCryptosslRSA::XrdCryptosslRSA(const char *pub, int lpub)
115{
116 // Constructor
117 // Allocate a RSA key pair and fill the public part importing
118 // from string representation (pub) to internal representation.
119 // If lpub>0 use the first lpub bytes; otherwise use strlen(pub)
120 // bytes.
121
122 fEVP = 0;
123 publen = -1;
124 prilen = -1;
125
126 // Import key
127 ImportPublic(pub,lpub);
128}
129
130//_____________________________________________________________________________
131XrdCryptosslRSA::XrdCryptosslRSA(EVP_PKEY *key, bool check)
132{
133 // Constructor to import existing key
134 EPNAME("RSA::XrdCryptosslRSA_key");
135
136 fEVP = 0;
137 publen = -1;
138 prilen = -1;
139
140 // Create container, first
141 if (!key) {
142 DEBUG("no input key");
143 return;
144 }
145
146 if (check) {
147 // Check consistency
148 if (XrdCheckRSA(key) == 1) {
149 fEVP = key;
150 // Update status
152 } else {
153 DEBUG("key contains inconsistent information");
154 }
155 } else {
156 // Accept in any case (for incomplete keys)
157 fEVP = key;
158 // Update status
159 status = kPublic;
160 }
161}
162
163
164//____________________________________________________________________________
166{
167 // Copy Constructor
168 EPNAME("RSA::XrdCryptosslRSA_copy");
169
170 fEVP = 0;
171 publen = -1;
172 prilen = -1;
173
174 if (!r.fEVP) {
175 DEBUG("input key is empty");
176 return;
177 }
178
179 // If the given key is set, copy it via a bio
180#if OPENSSL_VERSION_NUMBER >= 0x30000000L
181 BIGNUM *d = BN_new();
182 bool publiconly =
183 (EVP_PKEY_get_bn_param(r.fEVP, OSSL_PKEY_PARAM_RSA_D, &d) != 1);
184 BN_free(d);
185#else
186 const BIGNUM *d = 0;
187 RSA_get0_key(EVP_PKEY_get0_RSA(r.fEVP), 0, 0, &d);
188 bool publiconly = (d == 0);
189#endif
190 //
191 // Bio for exporting the pub key
192 BIO *bcpy = BIO_new(BIO_s_mem());
193 if (bcpy) {
194 bool ok;
195 if (publiconly) {
196 // Write kref public key to BIO
197 ok = (PEM_write_bio_PUBKEY(bcpy, r.fEVP) != 0);
198 } else {
199 // Write kref private key to BIO
200 ok = (PEM_write_bio_PrivateKey(bcpy,r.fEVP,0,0,0,0,0) != 0);
201 }
202 if (ok) {
203 if (publiconly) {
204 // Read public key from BIO
205 if ((fEVP = PEM_read_bio_PUBKEY(bcpy, 0, 0, 0))) {
206 status = kPublic;
207 }
208 } else {
209 if ((fEVP = PEM_read_bio_PrivateKey(bcpy,0,0,0))) {
210 // Check consistency only if original was not marked complete
211 if (r.status == kComplete || XrdCheckRSA(fEVP) == 1) {
212 // Update status
214 }
215 }
216 }
217 }
218 // Cleanup bio
219 BIO_free(bcpy);
220 }
221}
222
223//_____________________________________________________________________________
225{
226 // Destructor
227 // Destroy the RSA asymmetric key pair
228
229 if (fEVP)
230 EVP_PKEY_free(fEVP);
231 fEVP = 0;
232}
233
234//_____________________________________________________________________________
236{
237 // Get minimal length of output buffer
238
239 int lcmax = EVP_PKEY_size(fEVP) - 42;
240
241 return ((lin / lcmax) + 1) * EVP_PKEY_size(fEVP);
242}
243
244//_____________________________________________________________________________
245int XrdCryptosslRSA::ImportPublic(const char *pub, int lpub)
246{
247 // Import a public key
248 // Allocate a RSA key pair and fill the public part importing
249 // from string representation (pub) to internal representation.
250 // If lpub>0 use the first lpub bytes; otherwise use strlen(pub)
251 // bytes.
252 // Return 0 in case of success, -1 in case of failure
253
254 int rc = -1;
255 if (fEVP)
256 EVP_PKEY_free(fEVP);
257 fEVP = 0;
258 publen = -1;
259 prilen = -1;
260
261 // Temporary key
262 EVP_PKEY *keytmp = 0;
263
264 // Bio for exporting the pub key
265 BIO *bpub = BIO_new(BIO_s_mem());
266
267 // Check length
268 lpub = (lpub <= 0) ? strlen(pub) : lpub;
269
270 // Write key from pubexport to BIO
271 BIO_write(bpub,(void *)pub,lpub);
272
273 // Read pub key from BIO
274 if ((keytmp = PEM_read_bio_PUBKEY(bpub, 0, 0, 0))) {
275 fEVP = keytmp;
276 // Update status
277 status = kPublic;
278 rc = 0;
279 }
280 BIO_free(bpub);
281 return rc;
282}
283
284//_____________________________________________________________________________
285int XrdCryptosslRSA::ImportPrivate(const char *pri, int lpri)
286{
287 // Import a private key
288 // Fill the private part importing from string representation (pub) to
289 // internal representation.
290 // If lpub>0 use the first lpub bytes; otherwise use strlen(pub)
291 // bytes.
292 // Return 0 in case of success, -1 in case of failure
293
294 if (!fEVP)
295 return -1;
296
297 int rc = -1;
298 prilen = -1;
299
300 // Bio for exporting the pub key
301 BIO *bpri = BIO_new(BIO_s_mem());
302
303 // Check length
304 lpri = (lpri <= 0) ? strlen(pri) : lpri;
305
306 // Write key from private export to BIO
307 BIO_write(bpri,(void *)pri,lpri);
308
309 // Read private key from BIO
310 if (PEM_read_bio_PrivateKey(bpri, &fEVP, 0, 0)) {
311 // Update status
313 rc = 0;
314 }
315 BIO_free(bpri);
316 return rc;
317}
318
319//_____________________________________________________________________________
321{
322 // Dump some info about the key
323 EPNAME("RSA::Dump");
324
325 DEBUG("---------------------------------------");
326 DEBUG("address: "<<this);
327 if (IsValid()) {
328 char *btmp = new char[GetPublen()+1];
329 if (btmp) {
330 ExportPublic(btmp,GetPublen()+1);
331 DEBUG("export pub key:"<<std::endl<<btmp);
332 delete[] btmp;
333 } else {
334 DEBUG("cannot allocate memory for public key");
335 }
336 } else {
337 DEBUG("key is invalid");
338 }
339 DEBUG("---------------------------------------");
340}
341
342//_____________________________________________________________________________
344{
345 // Minimum length of export format of public key
346
347 if (publen < 0) {
348 // Bio for exporting the pub key
349 BIO *bkey = BIO_new(BIO_s_mem());
350 // Write public key to BIO
351 PEM_write_bio_PUBKEY(bkey,fEVP);
352 // data length
353 char *cbio = 0;
354 publen = (int) BIO_get_mem_data(bkey, &cbio);
355 BIO_free(bkey);
356 }
357 return publen;
358}
359//_____________________________________________________________________________
361{
362 // Export the public key into buffer out. The length of the buffer should be
363 // at least GetPublen()+1 bytes. The buffer out must be passed-by and it
364 // responsability-of the caller.
365 // Return 0 in case of success, -1 in case of failure
366 EPNAME("RSA::ExportPublic");
367
368 // Make sure we have a valid key
369 if (!IsValid()) {
370 DEBUG("key not valid");
371 return -1;
372 }
373
374 // Check output buffer
375 if (!out) {
376 DEBUG("output buffer undefined!");
377 return -1;
378 }
379
380 // Bio for exporting the pub key
381 BIO *bkey = BIO_new(BIO_s_mem());
382
383 // Write public key to BIO
384 PEM_write_bio_PUBKEY(bkey,fEVP);
385
386 // data length
387 char *cbio = 0;
388 int lbio = (int) BIO_get_mem_data(bkey, &cbio);
389 if (lbio <= 0 || !cbio) {
390 DEBUG("problems attaching to BIO content");
391 return -1;
392 }
393
394 // Read key from BIO to buf
395 memcpy(out, cbio, lbio);
396 // Null terminate
397 out[lbio] = 0;
398 DEBUG("("<<lbio<<" bytes) "<< std::endl <<out);
399 BIO_free(bkey);
400
401 return 0;
402}
403
404//_____________________________________________________________________________
406{
407 // Minimum length of export format of private key
408
409 if (prilen < 0) {
410 // Bio for exporting the private key
411 BIO *bkey = BIO_new(BIO_s_mem());
412 // Write public key to BIO
413 PEM_write_bio_PrivateKey(bkey,fEVP,0,0,0,0,0);
414 // data length
415 char *cbio = 0;
416 prilen = (int) BIO_get_mem_data(bkey, &cbio);
417 BIO_free(bkey);
418 }
419 return prilen;
420}
421
422//_____________________________________________________________________________
424{
425 // Export the private key into buffer out. The length of the buffer should be
426 // at least GetPrilen()+1 bytes. The buffer out must be passed-by and it
427 // responsability-of the caller.
428 // Return 0 in case of success, -1 in case of failure
429 EPNAME("RSA::ExportPrivate");
430
431 // Make sure we have a valid key
432 if (!IsValid()) {
433 DEBUG("key not valid");
434 return -1;
435 }
436
437 // Check output buffer
438 if (!out) {
439 DEBUG("output buffer undefined!");
440 return -1;
441 }
442
443 // Bio for exporting the pub key
444 BIO *bkey = BIO_new(BIO_s_mem());
445
446 // Write public key to BIO
447 PEM_write_bio_PrivateKey(bkey,fEVP,0,0,0,0,0);
448
449 // data length
450 char *cbio = 0;
451 int lbio = (int) BIO_get_mem_data(bkey, &cbio);
452 if (lbio <= 0 || !cbio) {
453 DEBUG("problems attaching to BIO content");
454 return -1;
455 }
456
457 // Read key from BIO to buf
458 memcpy(out, cbio, lbio);
459 // Null terminate
460 out[lbio] = 0;
461 DEBUG("("<<lbio<<" bytes) "<< std::endl <<out);
462 BIO_free(bkey);
463
464 return 0;
465}
466
467//_____________________________________________________________________________
468int XrdCryptosslRSA::EncryptPrivate(const char *in, int lin, char *out, int loutmax)
469{
470 // Encrypt lin bytes at 'in' using the internal private key.
471 // The output buffer 'out' is allocated by the caller for max lout bytes.
472 // The number of meaningful bytes in out is returned in case of success
473 // (never larger that loutmax); -1 in case of error.
474 EPNAME("RSA::EncryptPrivate");
475
476 // Make sure we got something to encrypt
477 if (!in || lin <= 0) {
478 DEBUG("input buffer undefined");
479 return -1;
480 }
481
482 // Make sure we got a buffer where to write
483 if (!out || loutmax <= 0) {
484 DEBUG("output buffer undefined");
485 return -1;
486 }
487
488 //
489 // Private encoding ...
490 size_t lcmax = EVP_PKEY_size(fEVP) - 11; // Magic number (= 2*sha1_outlen + 2)
491 size_t lout = 0;
492 size_t len = lin;
493 int kk = 0;
494 int ke = 0;
495
496 EVP_PKEY_CTX *ctx = EVP_PKEY_CTX_new(fEVP, 0);
497 EVP_PKEY_sign_init(ctx);
498 EVP_PKEY_CTX_set_rsa_padding(ctx, RSA_PKCS1_PADDING);
499 while (len > 0 && ke <= int(loutmax - lout)) {
500 size_t lc = (len > lcmax) ? lcmax : len;
501 lout = loutmax - ke;
502 if (EVP_PKEY_sign(ctx, (unsigned char *)&out[ke], &lout,
503 (unsigned char *)&in[kk], lc) <= 0) {
504 EVP_PKEY_CTX_free(ctx);
505 char serr[120];
506 ERR_error_string(ERR_get_error(), serr);
507 DEBUG("error: " <<serr);
508 return -1;
509 }
510 kk += lc;
511 ke += lout;
512 len -= lc;
513 }
514 EVP_PKEY_CTX_free(ctx);
515 if (len > 0 && ke > int(loutmax - lout))
516 DEBUG("buffer truncated");
517 lout = ke;
518
519 return lout;
520}
521
522//_____________________________________________________________________________
523int XrdCryptosslRSA::EncryptPublic(const char *in, int lin, char *out, int loutmax)
524{
525 // Encrypt lin bytes at 'in' using the internal public key.
526 // The output buffer 'out' is allocated by the caller for max lout bytes.
527 // The number of meaningful bytes in out is returned in case of success
528 // (never larger that loutmax); -1 in case of error.
529 EPNAME("RSA::EncryptPublic");
530
531 // Make sure we got something to encrypt
532 if (!in || lin <= 0) {
533 DEBUG("input buffer undefined");
534 return -1;
535 }
536
537 // Make sure we got a buffer where to write
538 if (!out || loutmax <= 0) {
539 DEBUG("output buffer undefined");
540 return -1;
541 }
542
543 //
544 // Public encoding ...
545 size_t lcmax = EVP_PKEY_size(fEVP) - 42; // Magic number (= 2*sha1_outlen + 2)
546 size_t lout = 0;
547 size_t len = lin;
548 int kk = 0;
549 int ke = 0;
550
551 EVP_PKEY_CTX *ctx = EVP_PKEY_CTX_new(fEVP, 0);
552 EVP_PKEY_encrypt_init(ctx);
553 EVP_PKEY_CTX_set_rsa_padding(ctx, RSA_PKCS1_OAEP_PADDING);
554 while (len > 0 && ke <= int(loutmax - lout)) {
555 size_t lc = (len > lcmax) ? lcmax : len;
556 lout = loutmax - ke;
557 if (EVP_PKEY_encrypt(ctx, (unsigned char *)&out[ke], &lout,
558 (unsigned char *)&in[kk], lc) <= 0) {
559 EVP_PKEY_CTX_free(ctx);
560 char serr[120];
561 ERR_error_string(ERR_get_error(), serr);
562 DEBUG("error: " <<serr);
563 return -1;
564 }
565 kk += lc;
566 ke += lout;
567 len -= lc;
568 }
569 EVP_PKEY_CTX_free(ctx);
570 if (len > 0 && ke > int(loutmax - lout))
571 DEBUG("buffer truncated");
572 lout = ke;
573
574 return lout;
575}
576
577//_____________________________________________________________________________
578int XrdCryptosslRSA::DecryptPrivate(const char *in, int lin, char *out, int loutmax)
579{
580 // Decrypt lin bytes at 'in' using the internal private key
581 // The output buffer 'out' is allocated by the caller for max lout bytes.
582 // The number of meaningful bytes in out is returned in case of success
583 // (never larger that loutmax); -1 in case of error.
584 EPNAME("RSA::DecryptPrivate");
585
586 // Make sure we got something to decrypt
587 if (!in || lin <= 0) {
588 DEBUG("input buffer undefined");
589 return -1;
590 }
591
592 // Make sure we got a buffer where to write
593 if (!out || loutmax <= 0) {
594 DEBUG("output buffer undefined");
595 return -1;
596 }
597
598 size_t lout = 0;
599 size_t len = lin;
600 size_t lcmax = EVP_PKEY_size(fEVP);
601 int kk = 0;
602 int ke = 0;
603
604 //
605 // Private decoding ...
606 EVP_PKEY_CTX *ctx = EVP_PKEY_CTX_new(fEVP, 0);
607 EVP_PKEY_decrypt_init(ctx);
608 EVP_PKEY_CTX_set_rsa_padding(ctx, RSA_PKCS1_OAEP_PADDING);
609 while (len > 0 && ke <= int(loutmax - lout)) {
610 lout = loutmax - ke;
611 if (EVP_PKEY_decrypt(ctx, (unsigned char *)&out[ke], &lout,
612 (unsigned char *)&in[kk], lcmax) <= 0) {
613 EVP_PKEY_CTX_free(ctx);
614 char serr[120];
615 ERR_error_string(ERR_get_error(), serr);
616 DEBUG("error: " <<serr);
617 return -1;
618 }
619 kk += lcmax;
620 len -= lcmax;
621 ke += lout;
622 }
623 EVP_PKEY_CTX_free(ctx);
624 if (len > 0 && ke > int(loutmax - lout))
625 PRINT("buffer truncated");
626 lout = ke;
627
628 return lout;
629}
630
631//_____________________________________________________________________________
632int XrdCryptosslRSA::DecryptPublic(const char *in, int lin, char *out, int loutmax)
633{
634 // Decrypt lin bytes at 'in' using the internal public key
635 // The output buffer 'out' is allocated by the caller for max lout bytes.
636 // The number of meaningful bytes in out is returned in case of success
637 // (never larger that loutmax); -1 in case of error.
638 EPNAME("RSA::DecryptPublic");
639
640 // Make sure we got something to decrypt
641 if (!in || lin <= 0) {
642 DEBUG("input buffer undefined");
643 return -1;
644 }
645
646 // Make sure we got a buffer where to write
647 if (!out || loutmax <= 0) {
648 DEBUG("output buffer undefined");
649 return -1;
650 }
651
652 size_t lout = 0;
653 size_t len = lin;
654 size_t lcmax = EVP_PKEY_size(fEVP);
655 int kk = 0;
656 int ke = 0;
657
658 //
659 // Private decoding ...
660 EVP_PKEY_CTX *ctx = EVP_PKEY_CTX_new(fEVP, 0);
661 EVP_PKEY_verify_recover_init(ctx);
662 EVP_PKEY_CTX_set_rsa_padding(ctx, RSA_PKCS1_PADDING);
663 while (len > 0 && ke <= int(loutmax - lout)) {
664 lout = loutmax - ke;
665 if (EVP_PKEY_verify_recover(ctx, (unsigned char *)&out[ke], &lout,
666 (unsigned char *)&in[kk], lcmax) <= 0) {
667 EVP_PKEY_CTX_free(ctx);
668 char serr[120];
669 ERR_error_string(ERR_get_error(), serr);
670 PRINT("error: " <<serr);
671 return -1;
672 }
673 kk += lcmax;
674 len -= lcmax;
675 ke += lout;
676 }
677 EVP_PKEY_CTX_free(ctx);
678 if (len > 0 && ke > int(loutmax - lout))
679 PRINT("buffer truncated");
680 lout = ke;
681
682 return lout;
683}
#define DEBUG(x)
#define EPNAME(x)
#define XrdCryptoMinRSABits
#define XrdCryptoDefRSAExp
#define XrdCryptoDefRSABits
static int XrdCheckRSA(EVP_PKEY *pkey)
#define PRINT(y)
static int XrdCheckRSA(EVP_PKEY *pkey)
ERSAStatus status
int EncryptPrivate(const char *in, int lin, char *out, int lout)
int ExportPublic(char *out, int lout)
int ImportPublic(const char *in, int lin)
XrdCryptosslRSA(int bits=XrdCryptoMinRSABits, int exp=XrdCryptoDefRSAExp)
int DecryptPrivate(const char *in, int lin, char *out, int lout)
int ExportPrivate(char *out, int lout)
int ImportPrivate(const char *in, int lin)
int GetOutlen(int lin)
virtual ~XrdCryptosslRSA()
int EncryptPublic(const char *in, int lin, char *out, int lout)
int DecryptPublic(const char *in, int lin, char *out, int lout)