nnoble | 0c475f0 | 2014-12-05 15:37:39 -0800 | [diff] [blame] | 1 | /* |
| 2 | * |
Jan Tattermusch | 7897ae9 | 2017-06-07 22:57:36 +0200 | [diff] [blame] | 3 | * Copyright 2015 gRPC authors. |
nnoble | 0c475f0 | 2014-12-05 15:37:39 -0800 | [diff] [blame] | 4 | * |
Jan Tattermusch | 7897ae9 | 2017-06-07 22:57:36 +0200 | [diff] [blame] | 5 | * Licensed under the Apache License, Version 2.0 (the "License"); |
| 6 | * you may not use this file except in compliance with the License. |
| 7 | * You may obtain a copy of the License at |
nnoble | 0c475f0 | 2014-12-05 15:37:39 -0800 | [diff] [blame] | 8 | * |
Jan Tattermusch | 7897ae9 | 2017-06-07 22:57:36 +0200 | [diff] [blame] | 9 | * http://www.apache.org/licenses/LICENSE-2.0 |
nnoble | 0c475f0 | 2014-12-05 15:37:39 -0800 | [diff] [blame] | 10 | * |
Jan Tattermusch | 7897ae9 | 2017-06-07 22:57:36 +0200 | [diff] [blame] | 11 | * Unless required by applicable law or agreed to in writing, software |
| 12 | * distributed under the License is distributed on an "AS IS" BASIS, |
| 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 14 | * See the License for the specific language governing permissions and |
| 15 | * limitations under the License. |
nnoble | 0c475f0 | 2014-12-05 15:37:39 -0800 | [diff] [blame] | 16 | * |
| 17 | */ |
| 18 | |
Nicolas "Pixel" Noble | d51d121 | 2016-01-31 11:33:19 +0100 | [diff] [blame] | 19 | #include <ruby/ruby.h> |
Nicolas "Pixel" Noble | 9fcdc87 | 2016-05-05 06:15:34 +0200 | [diff] [blame] | 20 | |
Nicolas "Pixel" Noble | d51d121 | 2016-01-31 11:33:19 +0100 | [diff] [blame] | 21 | #include "rb_grpc_imports.generated.h" |
nnoble | 0c475f0 | 2014-12-05 15:37:39 -0800 | [diff] [blame] | 22 | #include "rb_server_credentials.h" |
| 23 | |
nnoble | 0c475f0 | 2014-12-05 15:37:39 -0800 | [diff] [blame] | 24 | #include <grpc/grpc.h> |
| 25 | #include <grpc/grpc_security.h> |
murgatroid99 | 9acc40f | 2016-06-30 13:54:09 -0700 | [diff] [blame] | 26 | #include <grpc/support/log.h> |
nnoble | 0c475f0 | 2014-12-05 15:37:39 -0800 | [diff] [blame] | 27 | |
| 28 | #include "rb_grpc.h" |
| 29 | |
Yuki Yugui Sonoda | 3c88e5d | 2015-04-16 20:09:00 +0900 | [diff] [blame] | 30 | /* grpc_rb_cServerCredentials is the ruby class that proxies |
| 31 | grpc_server_credentials. */ |
| 32 | static VALUE grpc_rb_cServerCredentials = Qnil; |
| 33 | |
nnoble | 0c475f0 | 2014-12-05 15:37:39 -0800 | [diff] [blame] | 34 | /* grpc_rb_server_credentials wraps a grpc_server_credentials. It provides a |
murgatroid99 | 1fa96c5 | 2016-06-13 10:48:22 -0700 | [diff] [blame] | 35 | peer ruby object, 'mark' to hold references to objects involved in |
| 36 | constructing the server credentials. */ |
nnoble | 0c475f0 | 2014-12-05 15:37:39 -0800 | [diff] [blame] | 37 | typedef struct grpc_rb_server_credentials { |
| 38 | /* Holder of ruby objects involved in constructing the server credentials */ |
| 39 | VALUE mark; |
| 40 | /* The actual server credentials */ |
Craig Tiller | baa14a9 | 2017-11-03 09:09:36 -0700 | [diff] [blame] | 41 | grpc_server_credentials* wrapped; |
nnoble | 0c475f0 | 2014-12-05 15:37:39 -0800 | [diff] [blame] | 42 | } grpc_rb_server_credentials; |
| 43 | |
| 44 | /* Destroys the server credentials instances. */ |
Craig Tiller | baa14a9 | 2017-11-03 09:09:36 -0700 | [diff] [blame] | 45 | static void grpc_rb_server_credentials_free(void* p) { |
| 46 | grpc_rb_server_credentials* wrapper = NULL; |
nnoble | 0c475f0 | 2014-12-05 15:37:39 -0800 | [diff] [blame] | 47 | if (p == NULL) { |
| 48 | return; |
| 49 | }; |
Craig Tiller | baa14a9 | 2017-11-03 09:09:36 -0700 | [diff] [blame] | 50 | wrapper = (grpc_rb_server_credentials*)p; |
nnoble | 0c475f0 | 2014-12-05 15:37:39 -0800 | [diff] [blame] | 51 | |
| 52 | /* Delete the wrapped object if the mark object is Qnil, which indicates that |
| 53 | no other object is the actual owner. */ |
| 54 | if (wrapper->wrapped != NULL && wrapper->mark == Qnil) { |
| 55 | grpc_server_credentials_release(wrapper->wrapped); |
| 56 | wrapper->wrapped = NULL; |
| 57 | } |
| 58 | |
| 59 | xfree(p); |
| 60 | } |
| 61 | |
| 62 | /* Protects the mark object from GC */ |
Craig Tiller | baa14a9 | 2017-11-03 09:09:36 -0700 | [diff] [blame] | 63 | static void grpc_rb_server_credentials_mark(void* p) { |
| 64 | grpc_rb_server_credentials* wrapper = NULL; |
nnoble | 0c475f0 | 2014-12-05 15:37:39 -0800 | [diff] [blame] | 65 | if (p == NULL) { |
| 66 | return; |
| 67 | } |
Craig Tiller | baa14a9 | 2017-11-03 09:09:36 -0700 | [diff] [blame] | 68 | wrapper = (grpc_rb_server_credentials*)p; |
nnoble | 0c475f0 | 2014-12-05 15:37:39 -0800 | [diff] [blame] | 69 | |
| 70 | /* If it's not already cleaned up, mark the mark object */ |
| 71 | if (wrapper->mark != Qnil) { |
| 72 | rb_gc_mark(wrapper->mark); |
| 73 | } |
| 74 | } |
| 75 | |
Yuki Yugui Sonoda | 29ee1db | 2015-04-13 08:26:09 +0900 | [diff] [blame] | 76 | static const rb_data_type_t grpc_rb_server_credentials_data_type = { |
| 77 | "grpc_server_credentials", |
Deepak Lukose | dba4c5f | 2016-03-25 12:54:25 -0700 | [diff] [blame] | 78 | {grpc_rb_server_credentials_mark, |
| 79 | grpc_rb_server_credentials_free, |
| 80 | GRPC_RB_MEMSIZE_UNAVAILABLE, |
| 81 | {NULL, NULL}}, |
| 82 | NULL, |
| 83 | NULL, |
Tim Emiola | 9161a82 | 2015-11-11 15:58:44 -0800 | [diff] [blame] | 84 | #ifdef RUBY_TYPED_FREE_IMMEDIATELY |
Yuki Yugui Sonoda | 29ee1db | 2015-04-13 08:26:09 +0900 | [diff] [blame] | 85 | RUBY_TYPED_FREE_IMMEDIATELY |
Tim Emiola | 9161a82 | 2015-11-11 15:58:44 -0800 | [diff] [blame] | 86 | #endif |
Yuki Yugui Sonoda | 29ee1db | 2015-04-13 08:26:09 +0900 | [diff] [blame] | 87 | }; |
| 88 | |
nnoble | 0c475f0 | 2014-12-05 15:37:39 -0800 | [diff] [blame] | 89 | /* Allocates ServerCredential instances. |
| 90 | |
| 91 | Provides safe initial defaults for the instance fields. */ |
| 92 | static VALUE grpc_rb_server_credentials_alloc(VALUE cls) { |
Craig Tiller | baa14a9 | 2017-11-03 09:09:36 -0700 | [diff] [blame] | 93 | grpc_rb_server_credentials* wrapper = ALLOC(grpc_rb_server_credentials); |
nnoble | 0c475f0 | 2014-12-05 15:37:39 -0800 | [diff] [blame] | 94 | wrapper->wrapped = NULL; |
| 95 | wrapper->mark = Qnil; |
Yuki Yugui Sonoda | 29ee1db | 2015-04-13 08:26:09 +0900 | [diff] [blame] | 96 | return TypedData_Wrap_Struct(cls, &grpc_rb_server_credentials_data_type, |
| 97 | wrapper); |
nnoble | 0c475f0 | 2014-12-05 15:37:39 -0800 | [diff] [blame] | 98 | } |
| 99 | |
Tim Emiola | 14d0a3c | 2015-08-28 18:41:10 -0700 | [diff] [blame] | 100 | /* The attribute used on the mark object to preserve the pem_root_certs. */ |
nnoble | 0c475f0 | 2014-12-05 15:37:39 -0800 | [diff] [blame] | 101 | static ID id_pem_root_certs; |
| 102 | |
Tim Emiola | 14d0a3c | 2015-08-28 18:41:10 -0700 | [diff] [blame] | 103 | /* The attribute used on the mark object to preserve the pem_key_certs */ |
| 104 | static ID id_pem_key_certs; |
nnoble | 0c475f0 | 2014-12-05 15:37:39 -0800 | [diff] [blame] | 105 | |
Tim Emiola | 14d0a3c | 2015-08-28 18:41:10 -0700 | [diff] [blame] | 106 | /* The key used to access the pem cert in a key_cert pair hash */ |
| 107 | static VALUE sym_cert_chain; |
| 108 | |
| 109 | /* The key used to access the pem private key in a key_cert pair hash */ |
| 110 | static VALUE sym_private_key; |
nnoble | 0c475f0 | 2014-12-05 15:37:39 -0800 | [diff] [blame] | 111 | |
| 112 | /* |
| 113 | call-seq: |
Tim Emiola | 14d0a3c | 2015-08-28 18:41:10 -0700 | [diff] [blame] | 114 | creds = ServerCredentials.new(nil, |
| 115 | [{private_key: <pem_private_key1>, |
| 116 | {cert_chain: <pem_cert_chain1>}], |
| 117 | force_client_auth) |
| 118 | creds = ServerCredentials.new(pem_root_certs, |
| 119 | [{private_key: <pem_private_key1>, |
| 120 | {cert_chain: <pem_cert_chain1>}], |
| 121 | force_client_auth) |
nnoble | 0c475f0 | 2014-12-05 15:37:39 -0800 | [diff] [blame] | 122 | |
Tim Emiola | 14d0a3c | 2015-08-28 18:41:10 -0700 | [diff] [blame] | 123 | pem_root_certs: (optional) PEM encoding of the server root certificate |
| 124 | pem_private_key: (required) PEM encoding of the server's private keys |
| 125 | force_client_auth: indicatees |
nnoble | 0c475f0 | 2014-12-05 15:37:39 -0800 | [diff] [blame] | 126 | |
| 127 | Initializes ServerCredential instances. */ |
| 128 | static VALUE grpc_rb_server_credentials_init(VALUE self, VALUE pem_root_certs, |
Tim Emiola | 14d0a3c | 2015-08-28 18:41:10 -0700 | [diff] [blame] | 129 | VALUE pem_key_certs, |
| 130 | VALUE force_client_auth) { |
Craig Tiller | baa14a9 | 2017-11-03 09:09:36 -0700 | [diff] [blame] | 131 | grpc_rb_server_credentials* wrapper = NULL; |
| 132 | grpc_server_credentials* creds = NULL; |
| 133 | grpc_ssl_pem_key_cert_pair* key_cert_pairs = NULL; |
Tim Emiola | 14d0a3c | 2015-08-28 18:41:10 -0700 | [diff] [blame] | 134 | VALUE cert = Qnil; |
| 135 | VALUE key = Qnil; |
| 136 | VALUE key_cert = Qnil; |
| 137 | int auth_client = 0; |
Nicolas Noble | 86cbe30 | 2016-02-05 15:08:12 -0800 | [diff] [blame] | 138 | long num_key_certs = 0; |
Tim Emiola | 14d0a3c | 2015-08-28 18:41:10 -0700 | [diff] [blame] | 139 | int i; |
| 140 | |
| 141 | if (NIL_P(force_client_auth) || |
| 142 | !(force_client_auth == Qfalse || force_client_auth == Qtrue)) { |
| 143 | rb_raise(rb_eTypeError, |
| 144 | "bad force_client_auth: got:<%s> want: <True|False|nil>", |
| 145 | rb_obj_classname(force_client_auth)); |
| 146 | return Qnil; |
| 147 | } |
| 148 | if (NIL_P(pem_key_certs) || TYPE(pem_key_certs) != T_ARRAY) { |
| 149 | rb_raise(rb_eTypeError, "bad pem_key_certs: got:<%s> want: <Array>", |
| 150 | rb_obj_classname(pem_key_certs)); |
| 151 | return Qnil; |
| 152 | } |
| 153 | num_key_certs = RARRAY_LEN(pem_key_certs); |
| 154 | if (num_key_certs == 0) { |
| 155 | rb_raise(rb_eTypeError, "bad pem_key_certs: it had no elements"); |
| 156 | return Qnil; |
| 157 | } |
| 158 | for (i = 0; i < num_key_certs; i++) { |
| 159 | key_cert = rb_ary_entry(pem_key_certs, i); |
| 160 | if (key_cert == Qnil) { |
| 161 | rb_raise(rb_eTypeError, |
| 162 | "could not create a server credential: nil key_cert"); |
| 163 | return Qnil; |
| 164 | } else if (TYPE(key_cert) != T_HASH) { |
| 165 | rb_raise(rb_eTypeError, |
| 166 | "could not create a server credential: want <Hash>, got <%s>", |
| 167 | rb_obj_classname(key_cert)); |
| 168 | return Qnil; |
| 169 | } else if (rb_hash_aref(key_cert, sym_private_key) == Qnil) { |
| 170 | rb_raise(rb_eTypeError, |
| 171 | "could not create a server credential: want nil private key"); |
| 172 | return Qnil; |
| 173 | } else if (rb_hash_aref(key_cert, sym_cert_chain) == Qnil) { |
| 174 | rb_raise(rb_eTypeError, |
| 175 | "could not create a server credential: want nil cert chain"); |
| 176 | return Qnil; |
| 177 | } |
| 178 | } |
| 179 | |
Deepak Lukose | dba4c5f | 2016-03-25 12:54:25 -0700 | [diff] [blame] | 180 | auth_client = TYPE(force_client_auth) == T_TRUE |
| 181 | ? GRPC_SSL_REQUEST_AND_REQUIRE_CLIENT_CERTIFICATE_AND_VERIFY |
| 182 | : GRPC_SSL_DONT_REQUEST_CLIENT_CERTIFICATE; |
Tim Emiola | 14d0a3c | 2015-08-28 18:41:10 -0700 | [diff] [blame] | 183 | key_cert_pairs = ALLOC_N(grpc_ssl_pem_key_cert_pair, num_key_certs); |
| 184 | for (i = 0; i < num_key_certs; i++) { |
| 185 | key_cert = rb_ary_entry(pem_key_certs, i); |
| 186 | key = rb_hash_aref(key_cert, sym_private_key); |
| 187 | cert = rb_hash_aref(key_cert, sym_cert_chain); |
| 188 | key_cert_pairs[i].private_key = RSTRING_PTR(key); |
| 189 | key_cert_pairs[i].cert_chain = RSTRING_PTR(cert); |
| 190 | } |
| 191 | |
Yuki Yugui Sonoda | 29ee1db | 2015-04-13 08:26:09 +0900 | [diff] [blame] | 192 | TypedData_Get_Struct(self, grpc_rb_server_credentials, |
| 193 | &grpc_rb_server_credentials_data_type, wrapper); |
Tim Emiola | 14d0a3c | 2015-08-28 18:41:10 -0700 | [diff] [blame] | 194 | |
nnoble | 0c475f0 | 2014-12-05 15:37:39 -0800 | [diff] [blame] | 195 | if (pem_root_certs == Qnil) { |
Deepak Lukose | dba4c5f | 2016-03-25 12:54:25 -0700 | [diff] [blame] | 196 | creds = grpc_ssl_server_credentials_create_ex( |
| 197 | NULL, key_cert_pairs, num_key_certs, auth_client, NULL); |
nnoble | 0c475f0 | 2014-12-05 15:37:39 -0800 | [diff] [blame] | 198 | } else { |
Deepak Lukose | dba4c5f | 2016-03-25 12:54:25 -0700 | [diff] [blame] | 199 | creds = grpc_ssl_server_credentials_create_ex(RSTRING_PTR(pem_root_certs), |
| 200 | key_cert_pairs, num_key_certs, |
| 201 | auth_client, NULL); |
nnoble | 0c475f0 | 2014-12-05 15:37:39 -0800 | [diff] [blame] | 202 | } |
Tim Emiola | 14d0a3c | 2015-08-28 18:41:10 -0700 | [diff] [blame] | 203 | xfree(key_cert_pairs); |
nnoble | 0c475f0 | 2014-12-05 15:37:39 -0800 | [diff] [blame] | 204 | if (creds == NULL) { |
| 205 | rb_raise(rb_eRuntimeError, "could not create a credentials, not sure why"); |
Tim Emiola | 14d0a3c | 2015-08-28 18:41:10 -0700 | [diff] [blame] | 206 | return Qnil; |
nnoble | 0c475f0 | 2014-12-05 15:37:39 -0800 | [diff] [blame] | 207 | } |
| 208 | wrapper->wrapped = creds; |
| 209 | |
| 210 | /* Add the input objects as hidden fields to preserve them. */ |
Tim Emiola | 14d0a3c | 2015-08-28 18:41:10 -0700 | [diff] [blame] | 211 | rb_ivar_set(self, id_pem_key_certs, pem_key_certs); |
nnoble | 0c475f0 | 2014-12-05 15:37:39 -0800 | [diff] [blame] | 212 | rb_ivar_set(self, id_pem_root_certs, pem_root_certs); |
| 213 | |
| 214 | return self; |
| 215 | } |
| 216 | |
Tim Emiola | 409e6c8 | 2015-02-17 17:46:35 -0800 | [diff] [blame] | 217 | void Init_grpc_server_credentials() { |
Yuki Yugui Sonoda | a7d369e | 2015-04-11 11:48:36 +0900 | [diff] [blame] | 218 | grpc_rb_cServerCredentials = |
| 219 | rb_define_class_under(grpc_rb_mGrpcCore, "ServerCredentials", rb_cObject); |
nnoble | 0c475f0 | 2014-12-05 15:37:39 -0800 | [diff] [blame] | 220 | |
| 221 | /* Allocates an object managed by the ruby runtime */ |
Yuki Yugui Sonoda | a7d369e | 2015-04-11 11:48:36 +0900 | [diff] [blame] | 222 | rb_define_alloc_func(grpc_rb_cServerCredentials, |
| 223 | grpc_rb_server_credentials_alloc); |
nnoble | 0c475f0 | 2014-12-05 15:37:39 -0800 | [diff] [blame] | 224 | |
| 225 | /* Provides a ruby constructor and support for dup/clone. */ |
Yuki Yugui Sonoda | a7d369e | 2015-04-11 11:48:36 +0900 | [diff] [blame] | 226 | rb_define_method(grpc_rb_cServerCredentials, "initialize", |
nnoble | 0c475f0 | 2014-12-05 15:37:39 -0800 | [diff] [blame] | 227 | grpc_rb_server_credentials_init, 3); |
Yuki Yugui Sonoda | a7d369e | 2015-04-11 11:48:36 +0900 | [diff] [blame] | 228 | rb_define_method(grpc_rb_cServerCredentials, "initialize_copy", |
murgatroid99 | cc0f4e1 | 2016-06-02 16:00:54 -0700 | [diff] [blame] | 229 | grpc_rb_cannot_init_copy, 1); |
nnoble | 0c475f0 | 2014-12-05 15:37:39 -0800 | [diff] [blame] | 230 | |
Tim Emiola | 14d0a3c | 2015-08-28 18:41:10 -0700 | [diff] [blame] | 231 | id_pem_key_certs = rb_intern("__pem_key_certs"); |
nnoble | 0c475f0 | 2014-12-05 15:37:39 -0800 | [diff] [blame] | 232 | id_pem_root_certs = rb_intern("__pem_root_certs"); |
Tim Emiola | 14d0a3c | 2015-08-28 18:41:10 -0700 | [diff] [blame] | 233 | sym_private_key = ID2SYM(rb_intern("private_key")); |
| 234 | sym_cert_chain = ID2SYM(rb_intern("cert_chain")); |
nnoble | 0c475f0 | 2014-12-05 15:37:39 -0800 | [diff] [blame] | 235 | } |
| 236 | |
| 237 | /* Gets the wrapped grpc_server_credentials from the ruby wrapper */ |
Craig Tiller | baa14a9 | 2017-11-03 09:09:36 -0700 | [diff] [blame] | 238 | grpc_server_credentials* grpc_rb_get_wrapped_server_credentials(VALUE v) { |
| 239 | grpc_rb_server_credentials* wrapper = NULL; |
Yuki Yugui Sonoda | 29ee1db | 2015-04-13 08:26:09 +0900 | [diff] [blame] | 240 | TypedData_Get_Struct(v, grpc_rb_server_credentials, |
| 241 | &grpc_rb_server_credentials_data_type, wrapper); |
nnoble | 0c475f0 | 2014-12-05 15:37:39 -0800 | [diff] [blame] | 242 | return wrapper->wrapped; |
| 243 | } |