Ruby  2.5.0dev(2017-10-22revision60238)
ossl_ns_spki.c
Go to the documentation of this file.
1 /*
2  * 'OpenSSL for Ruby' project
3  * Copyright (C) 2001-2002 Michal Rokos <m.rokos@sh.cvut.cz>
4  * All rights reserved.
5  */
6 /*
7  * This program is licensed under the same licence as Ruby.
8  * (See the file 'LICENCE'.)
9  */
10 #include "ossl.h"
11 
12 #define NewSPKI(klass) \
13  TypedData_Wrap_Struct((klass), &ossl_netscape_spki_type, 0)
14 #define SetSPKI(obj, spki) do { \
15  if (!(spki)) { \
16  ossl_raise(rb_eRuntimeError, "SPKI wasn't initialized!"); \
17  } \
18  RTYPEDDATA_DATA(obj) = (spki); \
19 } while (0)
20 #define GetSPKI(obj, spki) do { \
21  TypedData_Get_Struct((obj), NETSCAPE_SPKI, &ossl_netscape_spki_type, (spki)); \
22  if (!(spki)) { \
23  ossl_raise(rb_eRuntimeError, "SPKI wasn't initialized!"); \
24  } \
25 } while (0)
26 
27 /*
28  * Classes
29  */
33 
34 /*
35  * Public functions
36  */
37 
38 /*
39  * Private functions
40  */
41 
42 static void
43 ossl_netscape_spki_free(void *spki)
44 {
45  NETSCAPE_SPKI_free(spki);
46 }
47 
48 static const rb_data_type_t ossl_netscape_spki_type = {
49  "OpenSSL/NETSCAPE_SPKI",
50  {
51  0, ossl_netscape_spki_free,
52  },
54 };
55 
56 static VALUE
57 ossl_spki_alloc(VALUE klass)
58 {
59  NETSCAPE_SPKI *spki;
60  VALUE obj;
61 
62  obj = NewSPKI(klass);
63  if (!(spki = NETSCAPE_SPKI_new())) {
65  }
66  SetSPKI(obj, spki);
67 
68  return obj;
69 }
70 
71 /*
72  * call-seq:
73  * SPKI.new([request]) => spki
74  *
75  * === Parameters
76  * * _request_ - optional raw request, either in PEM or DER format.
77  */
78 static VALUE
79 ossl_spki_initialize(int argc, VALUE *argv, VALUE self)
80 {
81  NETSCAPE_SPKI *spki;
82  VALUE buffer;
83  const unsigned char *p;
84 
85  if (rb_scan_args(argc, argv, "01", &buffer) == 0) {
86  return self;
87  }
88  StringValue(buffer);
89  if (!(spki = NETSCAPE_SPKI_b64_decode(RSTRING_PTR(buffer), RSTRING_LENINT(buffer)))) {
91  p = (unsigned char *)RSTRING_PTR(buffer);
92  if (!(spki = d2i_NETSCAPE_SPKI(NULL, &p, RSTRING_LEN(buffer)))) {
94  }
95  }
96  NETSCAPE_SPKI_free(DATA_PTR(self));
97  SetSPKI(self, spki);
98 
99  return self;
100 }
101 
102 /*
103  * call-seq:
104  * spki.to_der => DER-encoded string
105  *
106  * Returns the DER encoding of this SPKI.
107  */
108 static VALUE
109 ossl_spki_to_der(VALUE self)
110 {
111  NETSCAPE_SPKI *spki;
112  VALUE str;
113  long len;
114  unsigned char *p;
115 
116  GetSPKI(self, spki);
117  if ((len = i2d_NETSCAPE_SPKI(spki, NULL)) <= 0)
119  str = rb_str_new(0, len);
120  p = (unsigned char *)RSTRING_PTR(str);
121  if (i2d_NETSCAPE_SPKI(spki, &p) <= 0)
123  ossl_str_adjust(str, p);
124 
125  return str;
126 }
127 
128 /*
129  * call-seq:
130  * spki.to_pem => PEM-encoded string
131  *
132  * Returns the PEM encoding of this SPKI.
133  */
134 static VALUE
135 ossl_spki_to_pem(VALUE self)
136 {
137  NETSCAPE_SPKI *spki;
138  char *data;
139  VALUE str;
140 
141  GetSPKI(self, spki);
142  if (!(data = NETSCAPE_SPKI_b64_encode(spki))) {
144  }
145  str = ossl_buf2str(data, rb_long2int(strlen(data)));
146 
147  return str;
148 }
149 
150 /*
151  * call-seq:
152  * spki.to_text => string
153  *
154  * Returns a textual representation of this SPKI, useful for debugging
155  * purposes.
156  */
157 static VALUE
158 ossl_spki_print(VALUE self)
159 {
160  NETSCAPE_SPKI *spki;
161  BIO *out;
162 
163  GetSPKI(self, spki);
164  if (!(out = BIO_new(BIO_s_mem()))) {
166  }
167  if (!NETSCAPE_SPKI_print(out, spki)) {
168  BIO_free(out);
170  }
171 
172  return ossl_membio2str(out);
173 }
174 
175 /*
176  * call-seq:
177  * spki.public_key => pkey
178  *
179  * Returns the public key associated with the SPKI, an instance of
180  * OpenSSL::PKey.
181  */
182 static VALUE
183 ossl_spki_get_public_key(VALUE self)
184 {
185  NETSCAPE_SPKI *spki;
186  EVP_PKEY *pkey;
187 
188  GetSPKI(self, spki);
189  if (!(pkey = NETSCAPE_SPKI_get_pubkey(spki))) { /* adds an reference */
191  }
192 
193  return ossl_pkey_new(pkey); /* NO DUP - OK */
194 }
195 
196 /*
197  * call-seq:
198  * spki.public_key = pub => pkey
199  *
200  * === Parameters
201  * * _pub_ - the public key to be set for this instance
202  *
203  * Sets the public key to be associated with the SPKI, an instance of
204  * OpenSSL::PKey. This should be the public key corresponding to the
205  * private key used for signing the SPKI.
206  */
207 static VALUE
208 ossl_spki_set_public_key(VALUE self, VALUE key)
209 {
210  NETSCAPE_SPKI *spki;
211 
212  GetSPKI(self, spki);
213  if (!NETSCAPE_SPKI_set_pubkey(spki, GetPKeyPtr(key))) { /* NO NEED TO DUP */
215  }
216 
217  return key;
218 }
219 
220 /*
221  * call-seq:
222  * spki.challenge => string
223  *
224  * Returns the challenge string associated with this SPKI.
225  */
226 static VALUE
227 ossl_spki_get_challenge(VALUE self)
228 {
229  NETSCAPE_SPKI *spki;
230 
231  GetSPKI(self, spki);
232  if (spki->spkac->challenge->length <= 0) {
233  OSSL_Debug("Challenge.length <= 0?");
234  return rb_str_new(0, 0);
235  }
236 
237  return rb_str_new((const char *)spki->spkac->challenge->data,
238  spki->spkac->challenge->length);
239 }
240 
241 /*
242  * call-seq:
243  * spki.challenge = str => string
244  *
245  * === Parameters
246  * * _str_ - the challenge string to be set for this instance
247  *
248  * Sets the challenge to be associated with the SPKI. May be used by the
249  * server, e.g. to prevent replay.
250  */
251 static VALUE
252 ossl_spki_set_challenge(VALUE self, VALUE str)
253 {
254  NETSCAPE_SPKI *spki;
255 
256  StringValue(str);
257  GetSPKI(self, spki);
258  if (!ASN1_STRING_set(spki->spkac->challenge, RSTRING_PTR(str),
259  RSTRING_LENINT(str))) {
261  }
262 
263  return str;
264 }
265 
266 /*
267  * call-seq:
268  * spki.sign(key, digest) => spki
269  *
270  * === Parameters
271  * * _key_ - the private key to be used for signing this instance
272  * * _digest_ - the digest to be used for signing this instance
273  *
274  * To sign an SPKI, the private key corresponding to the public key set
275  * for this instance should be used, in addition to a digest algorithm in
276  * the form of an OpenSSL::Digest. The private key should be an instance of
277  * OpenSSL::PKey.
278  */
279 static VALUE
280 ossl_spki_sign(VALUE self, VALUE key, VALUE digest)
281 {
282  NETSCAPE_SPKI *spki;
283  EVP_PKEY *pkey;
284  const EVP_MD *md;
285 
286  pkey = GetPrivPKeyPtr(key); /* NO NEED TO DUP */
287  md = ossl_evp_get_digestbyname(digest);
288  GetSPKI(self, spki);
289  if (!NETSCAPE_SPKI_sign(spki, pkey, md)) {
291  }
292 
293  return self;
294 }
295 
296 /*
297  * call-seq:
298  * spki.verify(key) => boolean
299  *
300  * === Parameters
301  * * _key_ - the public key to be used for verifying the SPKI signature
302  *
303  * Returns +true+ if the signature is valid, +false+ otherwise. To verify an
304  * SPKI, the public key contained within the SPKI should be used.
305  */
306 static VALUE
307 ossl_spki_verify(VALUE self, VALUE key)
308 {
309  NETSCAPE_SPKI *spki;
310 
311  GetSPKI(self, spki);
312  switch (NETSCAPE_SPKI_verify(spki, GetPKeyPtr(key))) { /* NO NEED TO DUP */
313  case 0:
314  return Qfalse;
315  case 1:
316  return Qtrue;
317  default:
319  }
320  return Qnil; /* dummy */
321 }
322 
323 /* Document-class: OpenSSL::Netscape::SPKI
324  *
325  * A Simple Public Key Infrastructure implementation (pronounced "spooky").
326  * The structure is defined as
327  * PublicKeyAndChallenge ::= SEQUENCE {
328  * spki SubjectPublicKeyInfo,
329  * challenge IA5STRING
330  * }
331  *
332  * SignedPublicKeyAndChallenge ::= SEQUENCE {
333  * publicKeyAndChallenge PublicKeyAndChallenge,
334  * signatureAlgorithm AlgorithmIdentifier,
335  * signature BIT STRING
336  * }
337  * where the definitions of SubjectPublicKeyInfo and AlgorithmIdentifier can
338  * be found in RFC5280. SPKI is typically used in browsers for generating
339  * a public/private key pair and a subsequent certificate request, using
340  * the HTML <keygen> element.
341  *
342  * == Examples
343  *
344  * === Creating an SPKI
345  * key = OpenSSL::PKey::RSA.new 2048
346  * spki = OpenSSL::Netscape::SPKI.new
347  * spki.challenge = "RandomChallenge"
348  * spki.public_key = key.public_key
349  * spki.sign(key, OpenSSL::Digest::SHA256.new)
350  * #send a request containing this to a server generating a certificate
351  * === Verifying an SPKI request
352  * request = #...
353  * spki = OpenSSL::Netscape::SPKI.new request
354  * unless spki.verify(spki.public_key)
355  * # signature is invalid
356  * end
357  * #proceed
358  */
359 
360 /* Document-module: OpenSSL::Netscape
361  *
362  * OpenSSL::Netscape is a namespace for SPKI (Simple Public Key
363  * Infrastructure) which implements Signed Public Key and Challenge.
364  * See {RFC 2692}[http://tools.ietf.org/html/rfc2692] and {RFC
365  * 2693}[http://tools.ietf.org/html/rfc2692] for details.
366  */
367 
368 /* Document-class: OpenSSL::Netscape::SPKIError
369  *
370  * Generic Exception class that is raised if an error occurs during an
371  * operation on an instance of OpenSSL::Netscape::SPKI.
372  */
373 
374 void
376 {
377 #if 0
378  mOSSL = rb_define_module("OpenSSL");
380 #endif
381 
382  mNetscape = rb_define_module_under(mOSSL, "Netscape");
383 
385 
387 
388  rb_define_alloc_func(cSPKI, ossl_spki_alloc);
389  rb_define_method(cSPKI, "initialize", ossl_spki_initialize, -1);
390 
391  rb_define_method(cSPKI, "to_der", ossl_spki_to_der, 0);
392  rb_define_method(cSPKI, "to_pem", ossl_spki_to_pem, 0);
393  rb_define_alias(cSPKI, "to_s", "to_pem");
394  rb_define_method(cSPKI, "to_text", ossl_spki_print, 0);
395  rb_define_method(cSPKI, "public_key", ossl_spki_get_public_key, 0);
396  rb_define_method(cSPKI, "public_key=", ossl_spki_set_public_key, 1);
397  rb_define_method(cSPKI, "sign", ossl_spki_sign, 2);
398  rb_define_method(cSPKI, "verify", ossl_spki_verify, 1);
399  rb_define_method(cSPKI, "challenge", ossl_spki_get_challenge, 0);
400  rb_define_method(cSPKI, "challenge=", ossl_spki_set_challenge, 1);
401 }
VALUE mOSSL
Definition: ossl.c:231
#define NewSPKI(klass)
Definition: ossl_ns_spki.c:12
#define RUBY_TYPED_FREE_IMMEDIATELY
Definition: ruby.h:1138
size_t strlen(const char *)
VALUE eSPKIError
Definition: ossl_ns_spki.c:32
#define Qtrue
Definition: ruby.h:437
EVP_PKEY * GetPrivPKeyPtr(VALUE obj)
Definition: ossl_pkey.c:216
#define ossl_str_adjust(str, p)
Definition: ossl.h:82
#define rb_long2int(n)
Definition: ruby.h:319
VALUE rb_define_class_under(VALUE outer, const char *name, VALUE super)
Defines a class under the namespace of outer.
Definition: class.c:693
void rb_define_alloc_func(VALUE, rb_alloc_func_t)
#define DATA_PTR(dta)
Definition: ruby.h:1106
VALUE ossl_membio2str(BIO *bio)
Definition: ossl_bio.c:29
VALUE ossl_pkey_new(EVP_PKEY *pkey)
Definition: ossl_pkey.c:107
void ossl_clear_error(void)
Definition: ossl.c:304
VALUE eX509CertError
Definition: ossl_x509cert.c:31
RUBY_EXTERN VALUE rb_cObject
Definition: ruby.h:1893
VALUE eOSSLError
Definition: ossl.c:236
int argc
Definition: ruby.c:187
#define Qfalse
Definition: ruby.h:436
void rb_define_alias(VALUE klass, const char *name1, const char *name2)
Defines an alias of a method.
Definition: class.c:1758
#define RSTRING_LEN(str)
Definition: ruby.h:971
const EVP_MD * ossl_evp_get_digestbyname(VALUE obj)
Definition: ossl_digest.c:45
int rb_scan_args(int argc, const VALUE *argv, const char *fmt,...)
Definition: class.c:1908
#define Qnil
Definition: ruby.h:438
VALUE rb_eStandardError
Definition: error.c:799
unsigned long VALUE
Definition: ruby.h:85
#define OSSL_Debug
Definition: ossl.h:144
register unsigned int len
Definition: zonetab.h:51
void Init_ossl_ns_spki(void)
Definition: ossl_ns_spki.c:375
VALUE rb_define_module_under(VALUE outer, const char *name)
Definition: class.c:790
#define RSTRING_PTR(str)
Definition: ruby.h:975
#define SetSPKI(obj, spki)
Definition: ossl_ns_spki.c:14
VALUE ossl_buf2str(char *buf, int len)
Definition: ossl.c:120
VALUE mNetscape
Definition: ossl_ns_spki.c:30
void ossl_raise(VALUE exc, const char *fmt,...)
Definition: ossl.c:293
EVP_PKEY * GetPKeyPtr(VALUE obj)
Definition: ossl_pkey.c:206
#define RSTRING_LENINT(str)
Definition: ruby.h:983
VALUE rb_define_module(const char *name)
Definition: class.c:768
#define NULL
Definition: _sdbm.c:102
void rb_define_method(VALUE klass, const char *name, VALUE(*func)(ANYARGS), int argc)
Definition: class.c:1515
#define GetSPKI(obj, spki)
Definition: ossl_ns_spki.c:20
VALUE cSPKI
Definition: ossl_ns_spki.c:31
char ** argv
Definition: ruby.c:188
#define StringValue(v)
Definition: ruby.h:569
VALUE rb_str_new(const char *, long)
Definition: string.c:737