XRootD
XrdCryptosslX509Req.cc
Go to the documentation of this file.
1 /******************************************************************************/
2 /* */
3 /* X r d C r y p t o s s l X 5 0 9 R e q. c c */
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 /* OpenSSL implementation of XrdCryptoX509Req */
32 /* */
33 /* ************************************************************************** */
34 #include <sys/types.h>
35 #include <sys/stat.h>
36 #include <unistd.h>
37 #include <cerrno>
38 
43 
44 #include <openssl/pem.h>
45 
46 //_____________________________________________________________________________
48 {
49  // Constructor certificate from BIO 'bcer'
50  EPNAME("X509Req::XrdCryptosslX509Req_bio");
51 
52  // Init private members
53  creq = 0; // The certificate object
54  subject = ""; // subject;
55  subjecthash = ""; // hash of subject;
56  subjectoldhash = ""; // hash of subject (md5 algorithm);
57  bucket = 0; // bucket for serialization
58  pki = 0; // PKI of the certificate
59 
60  // Make sure we got something;
61  if (!buck) {
62  DEBUG("got undefined opaque buffer");
63  return;
64  }
65 
66  //
67  // Create a bio_mem to store the certificates
68  BIO *bmem = BIO_new(BIO_s_mem());
69  if (!bmem) {
70  DEBUG("unable to create BIO for memory operations");
71  return;
72  }
73 
74  // Write data to BIO
75  int nw = BIO_write(bmem,(const void *)(buck->buffer),buck->size);
76  if (nw != buck->size) {
77  DEBUG("problems writing data to memory BIO (nw: "<<nw<<")");
78  return;
79  }
80 
81  // Get certificate request from BIO
82  if (!PEM_read_bio_X509_REQ(bmem,&creq,0,0)) {
83  DEBUG("unable to read certificate request to memory BIO");
84  return;
85  }
86  //
87  // Free BIO
88  BIO_free(bmem);
89  //
90  // Init some of the private members (the others upon need)
91  Subject();
92  //
93  // Get the public key
94  EVP_PKEY *evpp = X509_REQ_get_pubkey(creq);
95  //
96  if (evpp) {
97  // init pki with the partial key
98  if (!pki)
99  pki = new XrdCryptosslRSA(evpp, 0);
100  } else {
101  DEBUG("could not access the public key");
102  }
103 }
104 
105 //_____________________________________________________________________________
107 {
108  // Constructor: import X509_REQ object
109  EPNAME("X509Req::XrdCryptosslX509Req_x509");
110 
111  // Init private members
112  creq = 0; // The certificate object
113  subject = ""; // subject;
114  subjecthash = ""; // hash of subject;
115  subjectoldhash = ""; // hash of subject (md5 algorithm);
116  bucket = 0; // bucket for serialization
117  pki = 0; // PKI of the certificate
118 
119  // Make sure we got something;
120  if (!xc) {
121  DEBUG("got undefined X509 object");
122  return;
123  }
124 
125  // Set certificate
126  creq = xc;
127  //
128  // Init some of the private members (the others upon need)
129  Subject();
130  //
131  // Get the public key
132  EVP_PKEY *evpp = X509_REQ_get_pubkey(creq);
133  //
134  if (evpp) {
135  // init pki with the partial key
136  if (!pki)
137  pki = new XrdCryptosslRSA(evpp, 0);
138  } else {
139  DEBUG("could not access the public key");
140  }
141 }
142 
143 //_____________________________________________________________________________
145 {
146  // Destructor
147 
148  // Cleanup certificate
149  if (creq) X509_REQ_free(creq);
150  // Cleanup key
151  if (pki) delete pki;
152 }
153 
154 //_____________________________________________________________________________
156 {
157  // Return subject name
158  EPNAME("X509Req::Subject");
159 
160  // If we do not have it already, try extraction
161  if (subject.length() <= 0) {
162 
163  // Make sure we have a certificate
164  if (!creq) {
165  DEBUG("WARNING: no certificate available - cannot extract subject name");
166  return (const char *)0;
167  }
168 
169  // Extract subject name
170  XrdCryptosslNameOneLine(X509_REQ_get_subject_name(creq), subject);
171  }
172 
173  // return what we have
174  return (subject.length() > 0) ? subject.c_str() : (const char *)0;
175 }
176 
177 //_____________________________________________________________________________
179 {
180  // Return hash of subject name
181  // Use default algorithm (X509_NAME_hash) for alg = 0, old algorithm
182  // (for v>=1.0.0) when alg = 1
183  EPNAME("X509::SubjectHash");
184 
185 #if (OPENSSL_VERSION_NUMBER >= 0x10000000L && !defined(__APPLE__))
186  if (alg == 1) {
187  // md5 based
188  if (subjectoldhash.length() <= 0) {
189  // Make sure we have a certificate
190  if (creq) {
191  char chash[30] = {0};
192  snprintf(chash, sizeof(chash),
193  "%08lx.0",X509_NAME_hash_old(X509_REQ_get_subject_name(creq)));
194  subjectoldhash = chash;
195  } else {
196  DEBUG("WARNING: no certificate available - cannot extract subject hash (md5)");
197  }
198  }
199  // return what we have
200  return (subjectoldhash.length() > 0) ? subjectoldhash.c_str() : (const char *)0;
201  }
202 #else
203  if (alg == 1) { }
204 #endif
205 
206  // If we do not have it already, try extraction
207  if (subjecthash.length() <= 0) {
208 
209  // Make sure we have a certificate
210  if (creq) {
211  char chash[30] = {0};
212  snprintf(chash, sizeof(chash),
213  "%08lx.0",X509_NAME_hash(X509_REQ_get_subject_name(creq)));
214  subjecthash = chash;
215  } else {
216  DEBUG("WARNING: no certificate available - cannot extract subject hash (default)");
217  }
218  }
219 
220  // return what we have
221  return (subjecthash.length() > 0) ? subjecthash.c_str() : (const char *)0;
222 }
223 
224 //_____________________________________________________________________________
226 {
227  // Return issuer name
228  EPNAME("X509Req::GetExtension");
229  XrdCryptoX509Reqdata ext = 0;
230 
231  // Make sure we got something to look for
232  if (!oid) {
233  DEBUG("OID string not defined");
234  return ext;
235  }
236 
237  // Make sure we got something to look for
238  if (!creq) {
239  DEBUG("certificate is not initialized");
240  return ext;
241  }
242 
243  // Are there any extension?
244  STACK_OF(X509_EXTENSION) *esk = X509_REQ_get_extensions(creq);
245  //
246 #if OPENSSL_VERSION_NUMBER >= 0x10000000L
247  int numext = sk_X509_EXTENSION_num(esk);
248 #else /* OPENSSL */
249  int numext = sk_num(esk);
250 #endif /* OPENSSL */
251  if (numext <= 0) {
252  DEBUG("certificate has got no extensions");
253  return ext;
254  }
255  DEBUG("certificate request has "<<numext<<" extensions");
256 
257  // If the string is the Standard Name of a known extension check
258  // searche the corresponding NID
259  int nid = OBJ_sn2nid(oid);
260  bool usenid = (nid > 0);
261 
262  // Loop to identify the one we would like
263  int i = 0;
264  X509_EXTENSION *wext = 0;
265  for (i = 0; i< numext; i++) {
266 #if OPENSSL_VERSION_NUMBER >= 0x10000000L
267  wext = sk_X509_EXTENSION_value(esk, i);
268 #else /* OPENSSL */
269  wext = (X509_EXTENSION *)sk_value(esk, i);
270 #endif /* OPENSSL */
271  if (usenid) {
272  int enid = OBJ_obj2nid(X509_EXTENSION_get_object(wext));
273  if (enid == nid)
274  break;
275  } else {
276  // Try matching of the text
277  char s[256];
278  OBJ_obj2txt(s, sizeof(s), X509_EXTENSION_get_object(wext), 1);
279  if (!strcmp(s, oid))
280  break;
281  }
282  wext = 0;
283  }
284 
285  // We are done if nothing was found
286  if (!wext) {
287  DEBUG("Extension "<<oid<<" not found");
288  return ext;
289  }
290 
291  // We are done
292  return (XrdCryptoX509Reqdata)wext;
293 }
294 
295 //_____________________________________________________________________________
297 {
298  // Export in form of bucket
299  EPNAME("X509Req::Export");
300 
301  // If we have already done it, return the previous result
302  if (bucket) {
303  DEBUG("serialization already performed:"
304  " return previous result ("<<bucket->size<<" bytes)");
305  return bucket;
306  }
307 
308  // Make sure we got something to export
309  if (!creq) {
310  DEBUG("certificate is not initialized");
311  return 0;
312  }
313 
314  //
315  // Now we create a bio_mem to serialize the certificate
316  BIO *bmem = BIO_new(BIO_s_mem());
317  if (!bmem) {
318  DEBUG("unable to create BIO for memory operations");
319  return 0;
320  }
321 
322  // Write certificate to BIO
323  if (!PEM_write_bio_X509_REQ(bmem, creq)) {
324  DEBUG("unable to write certificate request to memory BIO");
325  return 0;
326  }
327 
328  // Extract pointer to BIO data and length of segment
329  char *bdata = 0;
330  int blen = BIO_get_mem_data(bmem, &bdata);
331  DEBUG("BIO data: "<<blen<<" bytes at 0x"<<(int *)bdata);
332 
333  // create the bucket now
334  bucket = new XrdSutBucket(0,0,kXRS_x509_req);
335  if (bucket) {
336  // Fill bucket
337  bucket->SetBuf(bdata, blen);
338  DEBUG("result of serialization: "<<bucket->size<<" bytes");
339  } else {
340  DEBUG("unable to create bucket for serialized format");
341  BIO_free(bmem);
342  return 0;
343  }
344  //
345  // Free BIO
346  BIO_free(bmem);
347  //
348  // We are done
349  return bucket;
350 }
351 
352 //_____________________________________________________________________________
354 {
355  // Verify signature of the request
356  EPNAME("X509Req::Verify");
357 
358  // We must have been initialized
359  if (!creq)
360  return 0;
361 
362  // Ok: we can verify
363  int rc = X509_REQ_verify(creq,X509_REQ_get_pubkey(creq));
364  if (rc <= 0) {
365  // Failure
366  if (rc == 0) {
367  // Signatures are not OK
368  DEBUG("signature not OK");
369  } else {
370  // General failure
371  DEBUG("could not verify signature");
372  }
373  return 0;
374  }
375  // OK
376  return 1;
377 }
#define DEBUG(x)
Definition: XrdBwmTrace.hh:54
#define EPNAME(x)
Definition: XrdBwmTrace.hh:56
void * XrdCryptoX509Reqdata
void XrdCryptosslNameOneLine(X509_NAME *nm, XrdOucString &s)
@ kXRS_x509_req
Definition: XrdSutAux.hh:81
const char * SubjectHash()
XrdCryptosslX509Req(XrdSutBucket *bck)
XrdCryptoX509Reqdata GetExtension(const char *oid)
const char * c_str() const
int length() const
kXR_int32 size
Definition: XrdSutBucket.hh:47
int SetBuf(const char *nb=0, int ns=0)