XRootD
Loading...
Searching...
No Matches
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)
#define EPNAME(x)
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)
kXR_int32 size