libdigidocpp
RSACrypt.cpp
Go to the documentation of this file.
1 /*
2  * libdigidocpp
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2.1 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17  *
18  */
19 
20 #include <openssl/pem.h>
21 #include <openssl/err.h>
22 #include "../../log.h"
23 #include "../../crypto/cert/X509Cert.h"
24 #include "RSACrypt.h"
25 
32 digidoc::RSACrypt::RSACrypt(X509* cert, RSA* privateKey)
33  : cert(cert)
34  , privateKey(privateKey)
35 {
36 }
37 
44  : cert(cert)
45  , privateKey(NULL)
46 {
47 }
48 
55  : cert(NULL)
56  , privateKey(privateKey)
57 {
58 }
59 
64 {
65 }
66 
75 std::vector<unsigned char> digidoc::RSACrypt::sign(const Signer::Digest& digest) throw(IOException)
76 {
77  // Calculate memory needed for signature.
78  unsigned int blockSize = RSA_size(privateKey);
79  unsigned int neededSize = blockSize;
80  if(digest.length > blockSize)
81  {
82  if(digest.length % blockSize == 0)
83  neededSize = digest.length;
84  else
85  neededSize = ((digest.length / blockSize) + 1) * blockSize;
86  }
87 
88  // Allocate memory for the signature.
89  std::vector<unsigned char> signature(neededSize, 0);
90 
91  // Sign the digest with private RSA key.
92  unsigned int signatureLength = 0;
93  int result = RSA_sign(digest.type, digest.digest, digest.length, &signature[0], &signatureLength, privateKey);
94 
95  // Check that signing was successful.
96  if(result != 1)
97  {
98  THROW_IOEXCEPTION("Failed to sign the digest: %s", ERR_reason_error_string(ERR_get_error()));
99  }
100 
101  if(signatureLength != neededSize)
102  {
103  THROW_IOEXCEPTION("Failed to sign the digest.");
104  }
105 
106  return signature;
107 }
108 
120 bool digidoc::RSACrypt::verify(int digestMethod, std::vector<unsigned char> digest, std::vector<unsigned char> signature) throw(IOException)
121 {
122  // Check that X.509 certificate is set.
123  if(cert == NULL)
124  {
125  THROW_IOEXCEPTION("X.509 certificate parameter is not set in RSACrypt, can not verify signature.");
126  }
127 
128  // Extract RSA public key from X.509 certificate.
129  EVP_PKEY* key = X509_get_pubkey(cert);
130  if(!key || EVP_PKEY_type(key->type) != EVP_PKEY_RSA)
131  {
132  EVP_PKEY_free(key);
133  THROW_IOEXCEPTION("Certificate does not have a RSA public key, can not verify signature.");
134  }
135  RSA* publicKey = EVP_PKEY_get1_RSA(key);
136 
137  // Verify signature with RSA public key.
138  int result = RSA_verify(digestMethod, &digest[0], (unsigned int)digest.size(),
139  &signature[0], (unsigned int)signature.size(), publicKey);
140  RSA_free(publicKey);
141  EVP_PKEY_free(key);
142  return (result == 1);
143 }
144 
154 RSA* digidoc::RSACrypt::loadRSAPrivateKey(const std::string& path) throw(IOException)
155 {
156  // Initialize OpenSSL file.
157  BIO* file = BIO_new_file(path.c_str(), "rb");
158  if(file == NULL)
159  {
160  THROW_IOEXCEPTION("Failed to open RSA private key file '%s': %s",
161  path.c_str(), ERR_reason_error_string(ERR_get_error()));
162  }
163 
164  // Parse RSA private key from file.
165  RSA* key = PEM_read_bio_RSAPrivateKey(file, NULL, NULL, NULL);
166  BIO_free(file);
167  if(key == NULL)
168  {
169  THROW_IOEXCEPTION("Failed to load RSA private key from file '%s': %s",
170  path.c_str(), ERR_reason_error_string(ERR_get_error()));
171  }
172 
173  return key;
174 }