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 (alg == 1) {
186  // md5 based
187  if (subjectoldhash.length() <= 0) {
188  // Make sure we have a certificate
189  if (creq) {
190  char chash[30] = {0};
191  snprintf(chash, sizeof(chash),
192  "%08lx.0",X509_NAME_hash_old(X509_REQ_get_subject_name(creq)));
193  subjectoldhash = chash;
194  } else {
195  DEBUG("WARNING: no certificate available - cannot extract subject hash (md5)");
196  }
197  }
198  // return what we have
199  return (subjectoldhash.length() > 0) ? subjectoldhash.c_str() : (const char *)0;
200  }
201 
202  // If we do not have it already, try extraction
203  if (subjecthash.length() <= 0) {
204 
205  // Make sure we have a certificate
206  if (creq) {
207  char chash[30] = {0};
208  snprintf(chash, sizeof(chash),
209  "%08lx.0",X509_NAME_hash(X509_REQ_get_subject_name(creq)));
210  subjecthash = chash;
211  } else {
212  DEBUG("WARNING: no certificate available - cannot extract subject hash (default)");
213  }
214  }
215 
216  // return what we have
217  return (subjecthash.length() > 0) ? subjecthash.c_str() : (const char *)0;
218 }
219 
220 //_____________________________________________________________________________
222 {
223  // Return issuer name
224  EPNAME("X509Req::GetExtension");
225  XrdCryptoX509Reqdata ext = 0;
226 
227  // Make sure we got something to look for
228  if (!oid) {
229  DEBUG("OID string not defined");
230  return ext;
231  }
232 
233  // Make sure we got something to look for
234  if (!creq) {
235  DEBUG("certificate is not initialized");
236  return ext;
237  }
238 
239  // Are there any extension?
240  STACK_OF(X509_EXTENSION) *esk = X509_REQ_get_extensions(creq);
241  //
242  int numext = sk_X509_EXTENSION_num(esk);
243  if (numext <= 0) {
244  DEBUG("certificate has got no extensions");
245  return ext;
246  }
247  DEBUG("certificate request has "<<numext<<" extensions");
248 
249  // If the string is the Standard Name of a known extension check
250  // searche the corresponding NID
251  int nid = OBJ_sn2nid(oid);
252  bool usenid = (nid > 0);
253 
254  // Loop to identify the one we would like
255  int i = 0;
256  X509_EXTENSION *wext = 0;
257  for (i = 0; i< numext; i++) {
258  wext = sk_X509_EXTENSION_value(esk, i);
259  if (usenid) {
260  int enid = OBJ_obj2nid(X509_EXTENSION_get_object(wext));
261  if (enid == nid)
262  break;
263  } else {
264  // Try matching of the text
265  char s[256];
266  OBJ_obj2txt(s, sizeof(s), X509_EXTENSION_get_object(wext), 1);
267  if (!strcmp(s, oid))
268  break;
269  }
270  wext = 0;
271  }
272 
273  // We are done if nothing was found
274  if (!wext) {
275  DEBUG("Extension "<<oid<<" not found");
276  return ext;
277  }
278 
279  // We are done
280  return (XrdCryptoX509Reqdata)wext;
281 }
282 
283 //_____________________________________________________________________________
285 {
286  // Export in form of bucket
287  EPNAME("X509Req::Export");
288 
289  // If we have already done it, return the previous result
290  if (bucket) {
291  DEBUG("serialization already performed:"
292  " return previous result ("<<bucket->size<<" bytes)");
293  return bucket;
294  }
295 
296  // Make sure we got something to export
297  if (!creq) {
298  DEBUG("certificate is not initialized");
299  return 0;
300  }
301 
302  //
303  // Now we create a bio_mem to serialize the certificate
304  BIO *bmem = BIO_new(BIO_s_mem());
305  if (!bmem) {
306  DEBUG("unable to create BIO for memory operations");
307  return 0;
308  }
309 
310  // Write certificate to BIO
311  if (!PEM_write_bio_X509_REQ(bmem, creq)) {
312  DEBUG("unable to write certificate request to memory BIO");
313  return 0;
314  }
315 
316  // Extract pointer to BIO data and length of segment
317  char *bdata = 0;
318  int blen = BIO_get_mem_data(bmem, &bdata);
319  DEBUG("BIO data: "<<blen<<" bytes at 0x"<<(int *)bdata);
320 
321  // create the bucket now
322  bucket = new XrdSutBucket(0,0,kXRS_x509_req);
323  if (bucket) {
324  // Fill bucket
325  bucket->SetBuf(bdata, blen);
326  DEBUG("result of serialization: "<<bucket->size<<" bytes");
327  } else {
328  DEBUG("unable to create bucket for serialized format");
329  BIO_free(bmem);
330  return 0;
331  }
332  //
333  // Free BIO
334  BIO_free(bmem);
335  //
336  // We are done
337  return bucket;
338 }
339 
340 //_____________________________________________________________________________
342 {
343  // Verify signature of the request
344  EPNAME("X509Req::Verify");
345 
346  // We must have been initialized
347  if (!creq)
348  return 0;
349 
350  // Ok: we can verify
351  int rc = X509_REQ_verify(creq,X509_REQ_get_pubkey(creq));
352  if (rc <= 0) {
353  // Failure
354  if (rc == 0) {
355  // Signatures are not OK
356  DEBUG("signature not OK");
357  } else {
358  // General failure
359  DEBUG("could not verify signature");
360  }
361  return 0;
362  }
363  // OK
364  return 1;
365 }
#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)