1 /* 2 * 3 * Copyright 2015 gRPC authors. 4 * 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 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 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. 16 * 17 */ 18 19 #include <ruby/ruby.h> 20 21 #include "rb_grpc_imports.generated.h" 22 #include "rb_server_credentials.h" 23 24 #include <grpc/grpc.h> 25 #include <grpc/grpc_security.h> 26 #include <grpc/support/log.h> 27 28 #include "rb_grpc.h" 29 30 /* grpc_rb_cServerCredentials is the ruby class that proxies 31 grpc_server_credentials. */ 32 static VALUE grpc_rb_cServerCredentials = Qnil; 33 34 /* grpc_rb_server_credentials wraps a grpc_server_credentials. It provides a 35 peer ruby object, 'mark' to hold references to objects involved in 36 constructing the server credentials. */ 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 */ 41 grpc_server_credentials* wrapped; 42 } grpc_rb_server_credentials; 43 44 /* Destroys the server credentials instances. */ 45 static void grpc_rb_server_credentials_free(void* p) { 46 grpc_rb_server_credentials* wrapper = NULL; 47 if (p == NULL) { 48 return; 49 }; 50 wrapper = (grpc_rb_server_credentials*)p; 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 */ 63 static void grpc_rb_server_credentials_mark(void* p) { 64 grpc_rb_server_credentials* wrapper = NULL; 65 if (p == NULL) { 66 return; 67 } 68 wrapper = (grpc_rb_server_credentials*)p; 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 76 static const rb_data_type_t grpc_rb_server_credentials_data_type = { 77 "grpc_server_credentials", 78 {grpc_rb_server_credentials_mark, 79 grpc_rb_server_credentials_free, 80 GRPC_RB_MEMSIZE_UNAVAILABLE, 81 {NULL, NULL}}, 82 NULL, 83 NULL, 84 #ifdef RUBY_TYPED_FREE_IMMEDIATELY 85 RUBY_TYPED_FREE_IMMEDIATELY 86 #endif 87 }; 88 89 /* Allocates ServerCredential instances. 90 91 Provides safe initial defaults for the instance fields. */ 92 static VALUE grpc_rb_server_credentials_alloc(VALUE cls) { 93 grpc_rb_server_credentials* wrapper = ALLOC(grpc_rb_server_credentials); 94 wrapper->wrapped = NULL; 95 wrapper->mark = Qnil; 96 return TypedData_Wrap_Struct(cls, &grpc_rb_server_credentials_data_type, 97 wrapper); 98 } 99 100 /* The attribute used on the mark object to preserve the pem_root_certs. */ 101 static ID id_pem_root_certs; 102 103 /* The attribute used on the mark object to preserve the pem_key_certs */ 104 static ID id_pem_key_certs; 105 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; 111 112 /* 113 call-seq: 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) 122 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 126 127 Initializes ServerCredential instances. */ 128 static VALUE grpc_rb_server_credentials_init(VALUE self, VALUE pem_root_certs, 129 VALUE pem_key_certs, 130 VALUE force_client_auth) { 131 grpc_rb_server_credentials* wrapper = NULL; 132 grpc_server_credentials* creds = NULL; 133 grpc_ssl_pem_key_cert_pair* key_cert_pairs = NULL; 134 VALUE cert = Qnil; 135 VALUE key = Qnil; 136 VALUE key_cert = Qnil; 137 int auth_client = 0; 138 long num_key_certs = 0; 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 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; 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 192 TypedData_Get_Struct(self, grpc_rb_server_credentials, 193 &grpc_rb_server_credentials_data_type, wrapper); 194 195 if (pem_root_certs == Qnil) { 196 creds = grpc_ssl_server_credentials_create_ex( 197 NULL, key_cert_pairs, num_key_certs, auth_client, NULL); 198 } else { 199 creds = grpc_ssl_server_credentials_create_ex(RSTRING_PTR(pem_root_certs), 200 key_cert_pairs, num_key_certs, 201 auth_client, NULL); 202 } 203 xfree(key_cert_pairs); 204 if (creds == NULL) { 205 rb_raise(rb_eRuntimeError, "could not create a credentials, not sure why"); 206 return Qnil; 207 } 208 wrapper->wrapped = creds; 209 210 /* Add the input objects as hidden fields to preserve them. */ 211 rb_ivar_set(self, id_pem_key_certs, pem_key_certs); 212 rb_ivar_set(self, id_pem_root_certs, pem_root_certs); 213 214 return self; 215 } 216 217 void Init_grpc_server_credentials() { 218 grpc_rb_cServerCredentials = 219 rb_define_class_under(grpc_rb_mGrpcCore, "ServerCredentials", rb_cObject); 220 221 /* Allocates an object managed by the ruby runtime */ 222 rb_define_alloc_func(grpc_rb_cServerCredentials, 223 grpc_rb_server_credentials_alloc); 224 225 /* Provides a ruby constructor and support for dup/clone. */ 226 rb_define_method(grpc_rb_cServerCredentials, "initialize", 227 grpc_rb_server_credentials_init, 3); 228 rb_define_method(grpc_rb_cServerCredentials, "initialize_copy", 229 grpc_rb_cannot_init_copy, 1); 230 231 id_pem_key_certs = rb_intern("__pem_key_certs"); 232 id_pem_root_certs = rb_intern("__pem_root_certs"); 233 sym_private_key = ID2SYM(rb_intern("private_key")); 234 sym_cert_chain = ID2SYM(rb_intern("cert_chain")); 235 } 236 237 /* Gets the wrapped grpc_server_credentials from the ruby wrapper */ 238 grpc_server_credentials* grpc_rb_get_wrapped_server_credentials(VALUE v) { 239 grpc_rb_server_credentials* wrapper = NULL; 240 TypedData_Get_Struct(v, grpc_rb_server_credentials, 241 &grpc_rb_server_credentials_data_type, wrapper); 242 return wrapper->wrapped; 243 } 244