XRootD
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 
49 static 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) {
102  status = kComplete;
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 //_____________________________________________________________________________
114 XrdCryptosslRSA::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 //_____________________________________________________________________________
131 XrdCryptosslRSA::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
151  status = kComplete;
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
213  status = kComplete;
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 //_____________________________________________________________________________
245 int 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 //_____________________________________________________________________________
285 int 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
312  status = kComplete;
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 //_____________________________________________________________________________
360 int XrdCryptosslRSA::ExportPublic(char *out, int)
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 //_____________________________________________________________________________
468 int 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 //_____________________________________________________________________________
523 int 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 //_____________________________________________________________________________
578 int 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 //_____________________________________________________________________________
632 int 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)
Definition: XrdBwmTrace.hh:54
#define EPNAME(x)
Definition: XrdBwmTrace.hh:56
#define XrdCryptoMinRSABits
Definition: XrdCryptoAux.hh:52
#define XrdCryptoDefRSAExp
Definition: XrdCryptoAux.hh:54
#define XrdCryptoDefRSABits
Definition: XrdCryptoAux.hh:53
static int XrdCheckRSA(EVP_PKEY *pkey)
#define PRINT(y)
ERSAStatus status
Definition: XrdCryptoRSA.hh:58
bool IsValid()
Definition: XrdCryptoRSA.hh:69
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)