oversip_p 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/AUTHORS +22 -0
- data/LICENSE +25 -0
- data/README.md +43 -0
- data/Rakefile +54 -0
- data/bin/oversip +184 -0
- data/etc/oversip.conf +274 -0
- data/etc/proxies.conf +145 -0
- data/etc/server.rb +315 -0
- data/etc/tls/ca/cacert.pem +3894 -0
- data/etc/tls/demo-tls.oversip.net.crt +17 -0
- data/etc/tls/demo-tls.oversip.net.key +15 -0
- data/etc/tls/upgrade-cacert.sh +12 -0
- data/etc/tls/utils/create-cert.rb +162 -0
- data/etc/tls/utils/get-sip-identities.rb +95 -0
- data/ext/common/c_util.h +74 -0
- data/ext/common/ruby_c_util.h +88 -0
- data/ext/sip_parser/common_headers.h +210 -0
- data/ext/sip_parser/ext_help.h +18 -0
- data/ext/sip_parser/extconf.rb +3 -0
- data/ext/sip_parser/sip_message_parser.c +29741 -0
- data/ext/sip_parser/sip_parser.h +250 -0
- data/ext/sip_parser/sip_parser_ruby.c +1370 -0
- data/ext/sip_parser/sip_uri_parser.c +39699 -0
- data/ext/stud/extconf.rb +43 -0
- data/ext/stun/ext_help.h +16 -0
- data/ext/stun/extconf.rb +3 -0
- data/ext/stun/stun_ruby.c +394 -0
- data/ext/utils/ext_help.h +14 -0
- data/ext/utils/extconf.rb +3 -0
- data/ext/utils/haproxy_protocol.c +6163 -0
- data/ext/utils/haproxy_protocol.h +27 -0
- data/ext/utils/ip_utils.c +5952 -0
- data/ext/utils/ip_utils.h +64 -0
- data/ext/utils/outbound_utils.c +3227 -0
- data/ext/utils/outbound_utils.h +27 -0
- data/ext/utils/utils_ruby.c +392 -0
- data/ext/utils/utils_ruby.h +76 -0
- data/ext/websocket_framing_utils/ext_help.h +18 -0
- data/ext/websocket_framing_utils/extconf.rb +3 -0
- data/ext/websocket_framing_utils/ws_framing_utils.h +47 -0
- data/ext/websocket_framing_utils/ws_framing_utils_ruby.c +135 -0
- data/ext/websocket_http_parser/ext_help.h +18 -0
- data/ext/websocket_http_parser/extconf.rb +3 -0
- data/ext/websocket_http_parser/ws_http_parser.c +1635 -0
- data/ext/websocket_http_parser/ws_http_parser.h +87 -0
- data/ext/websocket_http_parser/ws_http_parser_ruby.c +630 -0
- data/lib/oversip/config.rb +597 -0
- data/lib/oversip/config_validators.rb +126 -0
- data/lib/oversip/default_server.rb +52 -0
- data/lib/oversip/errors.rb +10 -0
- data/lib/oversip/fiber_pool.rb +56 -0
- data/lib/oversip/launcher.rb +635 -0
- data/lib/oversip/logger.rb +84 -0
- data/lib/oversip/modules/outbound_mangling.rb +56 -0
- data/lib/oversip/modules/user_assertion.rb +73 -0
- data/lib/oversip/proxies_config.rb +189 -0
- data/lib/oversip/ruby_ext/eventmachine.rb +38 -0
- data/lib/oversip/sip/client.rb +428 -0
- data/lib/oversip/sip/client_transaction.rb +586 -0
- data/lib/oversip/sip/constants.rb +88 -0
- data/lib/oversip/sip/core.rb +217 -0
- data/lib/oversip/sip/launcher.rb +221 -0
- data/lib/oversip/sip/listeners/connection.rb +54 -0
- data/lib/oversip/sip/listeners/ipv4_tcp_client.rb +21 -0
- data/lib/oversip/sip/listeners/ipv4_tcp_server.rb +22 -0
- data/lib/oversip/sip/listeners/ipv4_tls_client.rb +21 -0
- data/lib/oversip/sip/listeners/ipv4_tls_server.rb +22 -0
- data/lib/oversip/sip/listeners/ipv4_tls_tunnel_server.rb +22 -0
- data/lib/oversip/sip/listeners/ipv4_udp_server.rb +21 -0
- data/lib/oversip/sip/listeners/ipv6_tcp_client.rb +21 -0
- data/lib/oversip/sip/listeners/ipv6_tcp_server.rb +22 -0
- data/lib/oversip/sip/listeners/ipv6_tls_client.rb +21 -0
- data/lib/oversip/sip/listeners/ipv6_tls_server.rb +22 -0
- data/lib/oversip/sip/listeners/ipv6_tls_tunnel_server.rb +22 -0
- data/lib/oversip/sip/listeners/ipv6_udp_server.rb +21 -0
- data/lib/oversip/sip/listeners/tcp_client.rb +97 -0
- data/lib/oversip/sip/listeners/tcp_connection.rb +202 -0
- data/lib/oversip/sip/listeners/tcp_server.rb +71 -0
- data/lib/oversip/sip/listeners/tls_client.rb +125 -0
- data/lib/oversip/sip/listeners/tls_server.rb +88 -0
- data/lib/oversip/sip/listeners/tls_tunnel_connection.rb +89 -0
- data/lib/oversip/sip/listeners/tls_tunnel_server.rb +61 -0
- data/lib/oversip/sip/listeners/udp_connection.rb +214 -0
- data/lib/oversip/sip/listeners.rb +24 -0
- data/lib/oversip/sip/message.rb +177 -0
- data/lib/oversip/sip/message_processor.rb +213 -0
- data/lib/oversip/sip/name_addr.rb +51 -0
- data/lib/oversip/sip/proxy.rb +324 -0
- data/lib/oversip/sip/request.rb +179 -0
- data/lib/oversip/sip/response.rb +37 -0
- data/lib/oversip/sip/rfc3263.rb +643 -0
- data/lib/oversip/sip/server_transaction.rb +295 -0
- data/lib/oversip/sip/sip.rb +76 -0
- data/lib/oversip/sip/tags.rb +39 -0
- data/lib/oversip/sip/timers.rb +55 -0
- data/lib/oversip/sip/transport_manager.rb +130 -0
- data/lib/oversip/sip/uac.rb +89 -0
- data/lib/oversip/sip/uac_request.rb +84 -0
- data/lib/oversip/sip/uri.rb +208 -0
- data/lib/oversip/syslog.rb +68 -0
- data/lib/oversip/system_callbacks.rb +45 -0
- data/lib/oversip/tls.rb +172 -0
- data/lib/oversip/utils.rb +30 -0
- data/lib/oversip/version.rb +21 -0
- data/lib/oversip/websocket/constants.rb +55 -0
- data/lib/oversip/websocket/http_request.rb +59 -0
- data/lib/oversip/websocket/launcher.rb +183 -0
- data/lib/oversip/websocket/listeners/connection.rb +51 -0
- data/lib/oversip/websocket/listeners/ipv4_ws_server.rb +22 -0
- data/lib/oversip/websocket/listeners/ipv4_wss_server.rb +22 -0
- data/lib/oversip/websocket/listeners/ipv4_wss_tunnel_server.rb +22 -0
- data/lib/oversip/websocket/listeners/ipv6_ws_server.rb +22 -0
- data/lib/oversip/websocket/listeners/ipv6_wss_server.rb +22 -0
- data/lib/oversip/websocket/listeners/ipv6_wss_tunnel_server.rb +22 -0
- data/lib/oversip/websocket/listeners/ws_server.rb +331 -0
- data/lib/oversip/websocket/listeners/wss_server.rb +88 -0
- data/lib/oversip/websocket/listeners/wss_tunnel_server.rb +133 -0
- data/lib/oversip/websocket/listeners.rb +13 -0
- data/lib/oversip/websocket/websocket.rb +13 -0
- data/lib/oversip/websocket/ws_framing.rb +545 -0
- data/lib/oversip/websocket/ws_sip_app.rb +120 -0
- data/lib/oversip.rb +127 -0
- data/test/oversip_test_helper.rb +19 -0
- data/test/test_http_parser.rb +73 -0
- data/test/test_name_addr.rb +27 -0
- data/test/test_name_addr_parser.rb +24 -0
- data/test/test_sip_message_parser.rb +168 -0
- data/test/test_sip_uri_parser.rb +56 -0
- data/test/test_uri.rb +68 -0
- data/thirdparty/stud/stud.tar.gz +0 -0
- metadata +334 -0
@@ -0,0 +1,17 @@
|
|
1
|
+
-----BEGIN CERTIFICATE-----
|
2
|
+
MIICrzCCAhigAwIBAgIET/1hdzANBgkqhkiG9w0BAQUFADBxMR0wGwYDVQQDDBRk
|
3
|
+
ZW1vLXRscy5vdmVyc2lwLm5ldDELMAkGA1UEBhMCRVMxEjAQBgNVBAoMCVZlcnNh
|
4
|
+
dGljYTEQMA4GA1UECwwHT3ZlclNJUDEdMBsGCgmSJomT8ixkAQMMDWliY0BhbGlh
|
5
|
+
eC5uZXQwHhcNMTIwNzEwMTEyMDMyWhcNMTcwNzEwMTEyMDMyWjBxMR0wGwYDVQQD
|
6
|
+
DBRkZW1vLXRscy5vdmVyc2lwLm5ldDELMAkGA1UEBhMCRVMxEjAQBgNVBAoMCVZl
|
7
|
+
cnNhdGljYTEQMA4GA1UECwwHT3ZlclNJUDEdMBsGCgmSJomT8ixkAQMMDWliY0Bh
|
8
|
+
bGlheC5uZXQwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBALXVloxokaERx4xL
|
9
|
+
0pH4rEe5liijlScKLGFJtpESUiG1pMTtWCxNzNTZ4J6mgdE07umS7567tHAEpRbr
|
10
|
+
C+yJ+VzoLNEpOf+x9zm83NTs3xg55SbhfVEL1vQqlnsfr5YG0iTy2znUPM3r3LVS
|
11
|
+
rTXz9UsIpnJO9ICvi28wz2a+HgStAgMBAAGjVDBSMAwGA1UdEwQFMAMBAf8wHQYD
|
12
|
+
VR0OBBYEFLMUKsF6Xm3uI2UnBTXZihnyOv90MCMGA1UdEQQcMBqGGHNpcDpkZW1v
|
13
|
+
LXRscy5vdmVyc2lwLm5ldDANBgkqhkiG9w0BAQUFAAOBgQAPj8XD5/snSPgjJocn
|
14
|
+
TpWqbOIbsQBMn11+sRpftf2SsC82wQ4iZy3E1nEDVItO+YzGkxtt2VV+uFoWYNKp
|
15
|
+
kzlTJDjvuE2lHwpiWgHIK4qcuC3NBYRKqopfmEtNj2vojQ3DPqyOA5v1YZyGw+SI
|
16
|
+
AhSZ8W6FTvfiHCO5ut/d7036VA==
|
17
|
+
-----END CERTIFICATE-----
|
@@ -0,0 +1,15 @@
|
|
1
|
+
-----BEGIN RSA PRIVATE KEY-----
|
2
|
+
MIICWwIBAAKBgQC11ZaMaJGhEceMS9KR+KxHuZYoo5UnCixhSbaRElIhtaTE7Vgs
|
3
|
+
TczU2eCepoHRNO7pku+eu7RwBKUW6wvsiflc6CzRKTn/sfc5vNzU7N8YOeUm4X1R
|
4
|
+
C9b0KpZ7H6+WBtIk8ts51DzN69y1Uq018/VLCKZyTvSAr4tvMM9mvh4ErQIDAQAB
|
5
|
+
AoGAVFzCOmaRmk8ra9YJ3hunoqdiGXy7yJ8ZtBGFGI2NeYJS7eLIU9XMwLxNUI4k
|
6
|
+
ELIkXk4Dynt/3bDp/1YR9C6XeFEZkmLcA3jbaX74/mcx6GgeCdAUg1bvrzpSFqyk
|
7
|
+
UYUw2ioFTKyfI1Z3VQmtWDxtz9BkHQ7uakOyu/HA8N8m0EECQQDe1velUoiQUTTn
|
8
|
+
DlsdrMvwFhBvJHstXzZMA6Rwp7HKwh6kmaqycr4Lv5UZX/6nzpqiM7EO7eCD6l9n
|
9
|
+
x7zIoOD5AkEA0OSHbCzJr0Wlxuq8joQe+ZXRz5BS+A3XWLG2ahnw/FdtLuxzNsWi
|
10
|
+
PdDiUOO4xdPoVj/9l2xwkPTfDLsxmDRiVQJAWfZ7QBkT3P+L1gQrsM1EAAdIVzZp
|
11
|
+
LCYWK5YE2x44Xt0Dtfv7t9Mu+ls7/GSO0HxOXVF1F8vdKiSCo8k1Y+HfMQJAcrLY
|
12
|
+
zQP2ph+2+/cOG67eFys1biQP+pYXBWNnBvFBij0y/U3loVB5Wjnk2od/gFhvvVQb
|
13
|
+
mVZ4pI9gHex3OdyhlQJAXNLuufGOEjnUC8lsmupiAQApMXscYPP0ahNES+hfX5uS
|
14
|
+
ylXyHsIJp7h6tBbK/bv/BW4HYFsWUpLbjl71EC2ymg==
|
15
|
+
-----END RSA PRIVATE KEY-----
|
@@ -0,0 +1,12 @@
|
|
1
|
+
#!/bin/bash
|
2
|
+
|
3
|
+
# This script downloads the Root CAs list from Mozilla and stores
|
4
|
+
# it under ca/ directory for TLS validation.
|
5
|
+
# cacert.pem is downloaded from http://curl.haxx.se/docs/caextract.html
|
6
|
+
# (the exact link is http://curl.haxx.se/ca/cacert.pem).
|
7
|
+
# cacert.pem is just downloaded in case the server version is newer than
|
8
|
+
# the local version of the file.
|
9
|
+
|
10
|
+
cd ca/
|
11
|
+
wget -N http://curl.haxx.se/ca/cacert.pem
|
12
|
+
|
@@ -0,0 +1,162 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require "openssl"
|
4
|
+
require "socket"
|
5
|
+
require "readline"
|
6
|
+
require "term/ansicolor"
|
7
|
+
|
8
|
+
|
9
|
+
module OverSIP
|
10
|
+
module Cert
|
11
|
+
|
12
|
+
class Error < ::StandardError ; end
|
13
|
+
|
14
|
+
extend Term::ANSIColor
|
15
|
+
|
16
|
+
def self.create_cert
|
17
|
+
|
18
|
+
begin
|
19
|
+
puts
|
20
|
+
puts bold(green("OverSIP TLS Certificate Generator"))
|
21
|
+
|
22
|
+
puts
|
23
|
+
puts bold("Certificate informational fields.")
|
24
|
+
|
25
|
+
ca = OpenSSL::X509::Name.new
|
26
|
+
|
27
|
+
cert_common_name = Readline.readline("- Common Name (eg, your name or your server's hostname): ").downcase.strip
|
28
|
+
cert_common_name = nil if cert_common_name.empty?
|
29
|
+
ca.add_entry "CN", cert_common_name if cert_common_name
|
30
|
+
|
31
|
+
cert_country_code = Readline.readline("- Country Name (2 letter code): ").upcase.strip
|
32
|
+
ca.add_entry "C", cert_country_code unless cert_country_code.empty?
|
33
|
+
|
34
|
+
cert_state = Readline.readline("- State or Province Name (full name): ").strip
|
35
|
+
ca.add_entry "ST", cert_state unless cert_state.empty?
|
36
|
+
|
37
|
+
cert_locality = Readline.readline("- Locality Name (eg, city): ").strip
|
38
|
+
ca.add_entry "L", cert_locality unless cert_locality.empty?
|
39
|
+
|
40
|
+
cert_organization = Readline.readline("- Organization Name (eg, company): ").strip
|
41
|
+
ca.add_entry "O", cert_organization unless cert_organization.empty?
|
42
|
+
|
43
|
+
cert_organization_unit = Readline.readline("- Organizational Unit Name (eg, section): ").strip
|
44
|
+
ca.add_entry "OU", cert_organization_unit unless cert_organization_unit.empty?
|
45
|
+
|
46
|
+
cert_mail = Readline.readline("- Email: ").strip
|
47
|
+
ca.add_entry "mail", cert_mail unless cert_mail.empty?
|
48
|
+
|
49
|
+
puts
|
50
|
+
puts bold("SubjectAltName SIP URI domains. ") + "For each given _domain_ an entry \"URI:sip:_domain_\" will be added to the SubjectAltName field."
|
51
|
+
cert_sipuri_domains = Readline.readline("- SubjectAltName SIP URI domains (multiple values separated by space): ").downcase.strip.split
|
52
|
+
cert_sipuri_domains = nil if cert_sipuri_domains.empty?
|
53
|
+
|
54
|
+
puts
|
55
|
+
puts bold("SubjectAltName DNS domains. ") + "For each given _domain_ an entry \"DNS:_domain_\" will be added to the SubjectAltName field."
|
56
|
+
cert_dns_domains = Readline.readline("- SubjectAltName DNS domains (multiple values separated by space): ").downcase.strip.split
|
57
|
+
cert_dns_domains = nil if cert_dns_domains.empty?
|
58
|
+
|
59
|
+
puts
|
60
|
+
puts bold("Signing data.")
|
61
|
+
|
62
|
+
rsa_key_bits = Readline.readline("- RSA key bits (1024/2048/4096) [1024]: ").strip.to_i
|
63
|
+
unless rsa_key_bits.zero?
|
64
|
+
unless [1024, 2048, 4096].include? rsa_key_bits
|
65
|
+
raise OverSIP::Cert::Error, "invalid number of bits (#{rsa_key_bits}) for RSA key"
|
66
|
+
end
|
67
|
+
else
|
68
|
+
rsa_key_bits = 1024
|
69
|
+
end
|
70
|
+
|
71
|
+
key = OpenSSL::PKey::RSA.generate(rsa_key_bits)
|
72
|
+
|
73
|
+
cert = OpenSSL::X509::Certificate.new
|
74
|
+
cert.version = 2
|
75
|
+
cert.subject = ca
|
76
|
+
cert.issuer = ca
|
77
|
+
cert.serial = Time.now.to_i
|
78
|
+
cert.public_key = key.public_key
|
79
|
+
|
80
|
+
years_to_expire = Readline.readline("- Expiration (in years from now) [1]: ").strip.to_i
|
81
|
+
years_to_expire = 1 if years_to_expire.zero?
|
82
|
+
cert.not_after = Time.now + (years_to_expire * 365 * 24 * 60 * 60)
|
83
|
+
cert.not_before = Time.now - (24 * 60 * 60)
|
84
|
+
|
85
|
+
factory = OpenSSL::X509::ExtensionFactory.new
|
86
|
+
factory.subject_certificate = cert
|
87
|
+
factory.issuer_certificate = cert
|
88
|
+
|
89
|
+
subject_alt_name_fields = []
|
90
|
+
|
91
|
+
cert_sipuri_domains.each do |sipuri_domain|
|
92
|
+
subject_alt_name_fields.<< "URI:sip:#{sipuri_domain}"
|
93
|
+
end if cert_sipuri_domains
|
94
|
+
|
95
|
+
cert_dns_domains.each do |dns_domain|
|
96
|
+
subject_alt_name_fields.<< "DNS:#{dns_domain}"
|
97
|
+
end if cert_dns_domains
|
98
|
+
|
99
|
+
extensions = {
|
100
|
+
"basicConstraints" => "CA:TRUE",
|
101
|
+
"subjectKeyIdentifier" => "hash"
|
102
|
+
}
|
103
|
+
if subject_alt_name_fields.any?
|
104
|
+
extensions["subjectAltName"] = subject_alt_name_fields.join(",")
|
105
|
+
end
|
106
|
+
|
107
|
+
cert.extensions = extensions.map {|k,v| factory.create_ext(k,v) }
|
108
|
+
|
109
|
+
cert.sign(key, OpenSSL::Digest::SHA1.new)
|
110
|
+
|
111
|
+
puts
|
112
|
+
puts bold("File name. ") + "For the given _name_ a public certificate _name_.crt and a private key _name_.key will be created. Also a file _name_.key.crt containing both the public certificate and the private key will be created."
|
113
|
+
file_name = Readline.readline("- File name [#{cert_common_name}]: ").strip
|
114
|
+
file_name = cert_common_name if file_name.empty?
|
115
|
+
unless file_name
|
116
|
+
raise OverSIP::Cert::Error, "a file name must be set"
|
117
|
+
end
|
118
|
+
|
119
|
+
puts
|
120
|
+
|
121
|
+
# Make two files:
|
122
|
+
# - file_name.crt => public certificate.
|
123
|
+
# - file_name.key => private key.
|
124
|
+
{"key" => key, "crt" => cert}.each_pair do |ext, o|
|
125
|
+
name = "#{file_name}.#{ext}"
|
126
|
+
File.open(name, "w") {|f| f.write(o.to_pem) }
|
127
|
+
File.chmod(0600, name) if ext == "key"
|
128
|
+
|
129
|
+
case ext
|
130
|
+
when "key"
|
131
|
+
puts yellow(">> private key generated in file '#{bold("#{name}")}'")
|
132
|
+
when "crt"
|
133
|
+
puts yellow(">> public certificate generated in file '#{bold("#{name}")}'")
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
# Make a single file containing both the public certificate and the private key.
|
138
|
+
name = "#{file_name}.key.crt"
|
139
|
+
File.open(name, "w") do |f|
|
140
|
+
f.write(cert.to_pem)
|
141
|
+
f.write(key.to_pem)
|
142
|
+
end
|
143
|
+
File.chmod(0600, name)
|
144
|
+
puts yellow(">> public certificate + private key generated in file '#{bold("#{name}")}'")
|
145
|
+
|
146
|
+
rescue ::Interrupt => e
|
147
|
+
puts "\n\n" + red("Interrupted")
|
148
|
+
exit
|
149
|
+
|
150
|
+
rescue ::OverSIP::Cert::Error => e
|
151
|
+
puts "\n" + bold(red("ERROR: #{e}"))
|
152
|
+
exit 1
|
153
|
+
end
|
154
|
+
|
155
|
+
end # def create_cert
|
156
|
+
|
157
|
+
end
|
158
|
+
end
|
159
|
+
|
160
|
+
|
161
|
+
OverSIP::Cert.create_cert
|
162
|
+
|
@@ -0,0 +1,95 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
# Runs as follows:
|
4
|
+
#
|
5
|
+
# ~$ ruby get-sip-identities.rb PEM_FILE
|
6
|
+
|
7
|
+
|
8
|
+
require "openssl"
|
9
|
+
|
10
|
+
|
11
|
+
module TLS
|
12
|
+
|
13
|
+
# Extracts the SIP identities in a public certificate following
|
14
|
+
# the mechanism in http://tools.ietf.org/html/rfc5922#section-7.1
|
15
|
+
# and returns an array containing them.
|
16
|
+
#
|
17
|
+
# Arguments:
|
18
|
+
# - _cert_: must be a public X.509 certificate in PEM format.
|
19
|
+
#
|
20
|
+
def self.get_sip_identities cert
|
21
|
+
puts "DEBUG: following rules in RFC 5922 \"Domain Certificates in SIP\" section 7.1 \"Finding SIP Identities in a Certificate\""
|
22
|
+
verify_subjectAltName_DNS = true
|
23
|
+
verify_CN = true
|
24
|
+
subjectAltName_URI_sip_entries = []
|
25
|
+
subjectAltName_DNS_entries = []
|
26
|
+
sip_identities = {}
|
27
|
+
|
28
|
+
cert.extensions.each do |ext|
|
29
|
+
next if ext.oid != "subjectAltName"
|
30
|
+
verify_CN = false
|
31
|
+
|
32
|
+
ext.value.split(/,\s+/).each do |name|
|
33
|
+
if /^URI:sip:([^@]*)/i =~ name
|
34
|
+
verify_subjectAltName_DNS = false
|
35
|
+
subjectAltName_URI_sip_entries << $1.downcase
|
36
|
+
elsif verify_subjectAltName_DNS && /^DNS:(.*)/i =~ name
|
37
|
+
subjectAltName_DNS_entries << $1.downcase
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
unless verify_CN
|
43
|
+
puts "DEBUG: certificate contains 'subjectAltName' extensions, 'CommonName' ignored"
|
44
|
+
unless verify_subjectAltName_DNS
|
45
|
+
subjectAltName_URI_sip_entries.each {|domain| sip_identities[domain] = true}
|
46
|
+
puts "DEBUG: 'subjectAltName' entries of type \"URI:sip:\" found, 'subjectAltName' entries of type \"DNS\" ignored"
|
47
|
+
else
|
48
|
+
subjectAltName_DNS_entries.each {|domain| sip_identities[domain] = true}
|
49
|
+
puts "DEBUG: 'subjectAltName' entries of type \"URI:sip:\" not found, using 'subjectAltName' entries of type \"DNS\""
|
50
|
+
end
|
51
|
+
|
52
|
+
else
|
53
|
+
puts "DEBUG: no 'subjectAltName' extension found, using 'CommonName' value"
|
54
|
+
cert.subject.to_a.each do |oid, value|
|
55
|
+
if oid == "CN"
|
56
|
+
sip_identities[value.downcase] = true
|
57
|
+
break
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
return sip_identities
|
63
|
+
end
|
64
|
+
|
65
|
+
end
|
66
|
+
|
67
|
+
|
68
|
+
unless (file = ARGV[0])
|
69
|
+
$stderr.puts "ERROR: no file given as argument"
|
70
|
+
exit false
|
71
|
+
end
|
72
|
+
|
73
|
+
unless ::File.file?(file) and ::File.readable?(file)
|
74
|
+
$stderr.puts "ERROR: given file is not a readable file"
|
75
|
+
exit false
|
76
|
+
end
|
77
|
+
|
78
|
+
begin
|
79
|
+
cert = ::OpenSSL::X509::Certificate.new(::File.read(file))
|
80
|
+
rescue => e
|
81
|
+
$stderr.puts "ERROR: cannot get a PEM certificate in the given file: #{e.message} (#{e.class})"
|
82
|
+
exit false
|
83
|
+
end
|
84
|
+
|
85
|
+
sip_identities = TLS.get_sip_identities cert
|
86
|
+
|
87
|
+
puts
|
88
|
+
if sip_identities.any?
|
89
|
+
puts "SIP identities found in the certificate:"
|
90
|
+
puts
|
91
|
+
sip_identities.each_key {|name| puts " - #{name}"}
|
92
|
+
else
|
93
|
+
puts "No SIP identities found in the certificate"
|
94
|
+
end
|
95
|
+
puts
|
data/ext/common/c_util.h
ADDED
@@ -0,0 +1,74 @@
|
|
1
|
+
/*
|
2
|
+
* Generic C functions and macros go here, there are no dependencies
|
3
|
+
* on OverSIP internal structures or the Ruby C API in here.
|
4
|
+
*/
|
5
|
+
|
6
|
+
#ifndef c_util_h
|
7
|
+
#define c_util_h
|
8
|
+
|
9
|
+
|
10
|
+
#define ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0]))
|
11
|
+
|
12
|
+
|
13
|
+
/*
|
14
|
+
* str_to_int: Given a pointer to char and length returns an int (but just possitive).
|
15
|
+
*/
|
16
|
+
static int str_to_int(const char* str, size_t len)
|
17
|
+
{
|
18
|
+
TRACE();
|
19
|
+
int number = 0;
|
20
|
+
const char *s = str;
|
21
|
+
|
22
|
+
while (len--) {
|
23
|
+
/* Ignore zeroes at the beginning. */
|
24
|
+
if (number || *s != '0')
|
25
|
+
number = number*10 + (*s)-'0';
|
26
|
+
s++;
|
27
|
+
}
|
28
|
+
return number;
|
29
|
+
}
|
30
|
+
|
31
|
+
|
32
|
+
/*
|
33
|
+
* strnchr: Find the first character in a length limited string.
|
34
|
+
* @s: The string to be searched
|
35
|
+
* @len: The number of characters to be searched
|
36
|
+
* @c: The character to search for
|
37
|
+
*/
|
38
|
+
static char *strnchr(const char *s, size_t len, size_t c)
|
39
|
+
{
|
40
|
+
TRACE();
|
41
|
+
for (; len--; ++s)
|
42
|
+
if (*s == (char)c)
|
43
|
+
return (char *)s;
|
44
|
+
return NULL;
|
45
|
+
}
|
46
|
+
|
47
|
+
|
48
|
+
/*
|
49
|
+
* str_find_upcase: Returns non zero if the string (*str, len) contains at least
|
50
|
+
* an upcase letter.
|
51
|
+
*/
|
52
|
+
static char *str_find_upcase(const char *s, size_t len)
|
53
|
+
{
|
54
|
+
TRACE();
|
55
|
+
for (; len--; ++s)
|
56
|
+
if (*s >= 'A' && *s <= 'Z')
|
57
|
+
return (char *)s;
|
58
|
+
return NULL;
|
59
|
+
}
|
60
|
+
|
61
|
+
|
62
|
+
/*
|
63
|
+
* capitalizes all lower-case ASCII characters.
|
64
|
+
*/
|
65
|
+
static void downcase_char(char *c)
|
66
|
+
{
|
67
|
+
TRACE();
|
68
|
+
if (*c >= 'A' && *c <= 'Z')
|
69
|
+
*c += 32;
|
70
|
+
}
|
71
|
+
|
72
|
+
|
73
|
+
#endif
|
74
|
+
|
@@ -0,0 +1,88 @@
|
|
1
|
+
/*
|
2
|
+
* Generic Ruby C functions and macros go here.
|
3
|
+
*/
|
4
|
+
|
5
|
+
#ifndef ruby_c_util_h
|
6
|
+
#define ruby_c_util_h
|
7
|
+
|
8
|
+
|
9
|
+
#include <ruby.h>
|
10
|
+
#include <ruby/encoding.h> /* Required: http://redmine.ruby-lang.org/issues/show/4272 */
|
11
|
+
#include "c_util.h"
|
12
|
+
|
13
|
+
|
14
|
+
#define RB_STR_UTF8_NEW(s, len) (rb_enc_str_new(s, len, rb_utf8_encoding()))
|
15
|
+
|
16
|
+
|
17
|
+
/*
|
18
|
+
* my_rb_str_hex_unescape: Unescapes hexadecimal encoded symbols (%NN).
|
19
|
+
*/
|
20
|
+
static VALUE my_rb_str_hex_unescape(const char *str, size_t len)
|
21
|
+
{
|
22
|
+
TRACE();
|
23
|
+
/* Check if hexadecimal unescaping is required. */
|
24
|
+
if (strnchr(str, len, '%')) {
|
25
|
+
char *new_str;
|
26
|
+
VALUE str_unescaped;
|
27
|
+
|
28
|
+
new_str = ALLOC_N(char, len);
|
29
|
+
memcpy(new_str, str, len);
|
30
|
+
|
31
|
+
char *s, *t;
|
32
|
+
char hex[3] = {0, 0, 0};
|
33
|
+
int i;
|
34
|
+
|
35
|
+
for (s = t = new_str, i = 0 ; i < len ; s++, i++) {
|
36
|
+
if (*s != '%' || !(*(s+1)) || !(*(s+2)))
|
37
|
+
*t++ = *s;
|
38
|
+
else {
|
39
|
+
hex[0] = *(s+1);
|
40
|
+
hex[1] = *(s+2);
|
41
|
+
*t++ = (strtol(hex, NULL, 16) & 0xFF);
|
42
|
+
s += 2;
|
43
|
+
len -= 2;
|
44
|
+
}
|
45
|
+
}
|
46
|
+
|
47
|
+
str_unescaped = RB_STR_UTF8_NEW(new_str, len);
|
48
|
+
xfree(new_str);
|
49
|
+
return(str_unescaped);
|
50
|
+
}
|
51
|
+
/* If unescaping is not required, then create a Ruby string with original pointer and length. */
|
52
|
+
else
|
53
|
+
return(RB_STR_UTF8_NEW(str, len));
|
54
|
+
}
|
55
|
+
|
56
|
+
/*
|
57
|
+
* my_rb_str_downcase: Downcases a string formed by simple symbols (ASCII).
|
58
|
+
*/
|
59
|
+
static VALUE my_rb_str_downcase(const char *str, size_t len)
|
60
|
+
{
|
61
|
+
TRACE();
|
62
|
+
/* Check if there is at least an upcase char. */
|
63
|
+
if (str_find_upcase(str, len)) {
|
64
|
+
char *new_str;
|
65
|
+
VALUE str_downcased;
|
66
|
+
|
67
|
+
new_str = ALLOC_N(char, len);
|
68
|
+
memcpy(new_str, str, len);
|
69
|
+
|
70
|
+
char *s;
|
71
|
+
int i;
|
72
|
+
|
73
|
+
for (s = new_str, i = 0 ; i < len ; s++, i++)
|
74
|
+
if (*s >= 'A' && *s <= 'Z')
|
75
|
+
*s += 32;
|
76
|
+
|
77
|
+
str_downcased = RB_STR_UTF8_NEW(new_str, len);
|
78
|
+
xfree(new_str);
|
79
|
+
return(str_downcased);
|
80
|
+
}
|
81
|
+
/* If not, then create a Ruby string with original pointer and length. */
|
82
|
+
else
|
83
|
+
return(RB_STR_UTF8_NEW(str, len));
|
84
|
+
}
|
85
|
+
|
86
|
+
|
87
|
+
#endif
|
88
|
+
|
@@ -0,0 +1,210 @@
|
|
1
|
+
#ifndef common_headers_h
|
2
|
+
#define common_headers_h
|
3
|
+
|
4
|
+
#include "../common/c_util.h"
|
5
|
+
#include "ruby.h"
|
6
|
+
#include <ctype.h> // toupper()
|
7
|
+
|
8
|
+
|
9
|
+
/* There are 20 headers with sort representation. */
|
10
|
+
#define NUM_SHORT_HEADERS 20
|
11
|
+
|
12
|
+
|
13
|
+
struct common_header_name {
|
14
|
+
const signed long len;
|
15
|
+
const char *name;
|
16
|
+
VALUE value;
|
17
|
+
const char short_name;
|
18
|
+
};
|
19
|
+
|
20
|
+
|
21
|
+
struct short_header {
|
22
|
+
char abbr;
|
23
|
+
VALUE value;
|
24
|
+
};
|
25
|
+
|
26
|
+
|
27
|
+
/*
|
28
|
+
* A list of common SIP headers we expect to receive.
|
29
|
+
* This allows us to avoid repeatedly creating identical string
|
30
|
+
* objects to be used with rb_hash_aset().
|
31
|
+
*/
|
32
|
+
static struct common_header_name common_headers[] = {
|
33
|
+
#define f(N, S) { (sizeof(N) - 1), N, Qnil, S }
|
34
|
+
f("Accept", ' '),
|
35
|
+
f("Accept-Contact", 'A'),
|
36
|
+
f("Accept-Encoding", ' '),
|
37
|
+
f("Accept-Language", ' '),
|
38
|
+
f("Alert-Info", ' '),
|
39
|
+
f("Allow", ' '),
|
40
|
+
f("Allow-Events", 'U'),
|
41
|
+
f("Authentication-Info", ' '),
|
42
|
+
f("Authorization", ' '),
|
43
|
+
f("Call-ID", 'I'),
|
44
|
+
f("Call-Info", ' '),
|
45
|
+
f("Contact", 'M'),
|
46
|
+
f("Content-Disposition", ' '),
|
47
|
+
f("Content-Encoding", 'E'),
|
48
|
+
f("Content-Language", ' '),
|
49
|
+
f("Content-Length", 'L'),
|
50
|
+
f("Content-Type", 'C'),
|
51
|
+
f("CSeq", ' '),
|
52
|
+
f("Date", ' '),
|
53
|
+
f("Event", 'O'),
|
54
|
+
f("Error-Info", ' '),
|
55
|
+
f("Expires", ' '),
|
56
|
+
f("From", 'F'),
|
57
|
+
f("Identity", 'Y'),
|
58
|
+
f("Identity-Info", 'N'),
|
59
|
+
f("In-Reply-To", ' '),
|
60
|
+
f("Max-Forwards", ' '),
|
61
|
+
f("Min-Expires", ' '),
|
62
|
+
f("MIME-Version", ' '),
|
63
|
+
f("Organization", ' '),
|
64
|
+
f("Priority", ' '),
|
65
|
+
f("Proxy-Authenticate", ' '),
|
66
|
+
f("Proxy-Authorization", ' '),
|
67
|
+
f("Proxy-Require", ' '),
|
68
|
+
f("Record-Route", ' '),
|
69
|
+
f("Refer-To", 'R'),
|
70
|
+
f("Referred-By", 'B'),
|
71
|
+
f("Reject-Contact", 'J'),
|
72
|
+
f("Reply-To", ' '),
|
73
|
+
f("Request-Disposition", 'D'),
|
74
|
+
f("Require", ' '),
|
75
|
+
f("Retry-After", ' '),
|
76
|
+
f("Route", ' '),
|
77
|
+
f("Server", ' '),
|
78
|
+
f("Session-Expires", 'X'),
|
79
|
+
f("Subject", 'S'),
|
80
|
+
f("Supported", 'K'),
|
81
|
+
f("Timestamp", ' '),
|
82
|
+
f("To", 'T'),
|
83
|
+
f("Unsupported", ' '),
|
84
|
+
f("User-Agent", ' '),
|
85
|
+
f("Via", 'V'),
|
86
|
+
f("Warning", ' '),
|
87
|
+
f("WWW-Authenticate", ' ')
|
88
|
+
# undef f
|
89
|
+
};
|
90
|
+
|
91
|
+
|
92
|
+
/*
|
93
|
+
* The list of short headers. This list is filled by the funcion
|
94
|
+
* init_short_header_names.
|
95
|
+
*/
|
96
|
+
static struct short_header short_headers[NUM_SHORT_HEADERS];
|
97
|
+
|
98
|
+
|
99
|
+
/* this function is not performance-critical, called only at load time */
|
100
|
+
static void init_common_headers(void)
|
101
|
+
{
|
102
|
+
TRACE();
|
103
|
+
int i;
|
104
|
+
struct common_header_name *cf = common_headers;
|
105
|
+
|
106
|
+
for(i = ARRAY_SIZE(common_headers); --i >= 0; cf++) {
|
107
|
+
cf->value = rb_str_new(cf->name, cf->len);
|
108
|
+
cf->value = rb_obj_freeze(cf->value);
|
109
|
+
/* This tell Ruby not to GC global variables which refer to Ruby's objects,
|
110
|
+
but are not exported to the Ruby world. */
|
111
|
+
rb_global_variable(&cf->value);
|
112
|
+
}
|
113
|
+
}
|
114
|
+
|
115
|
+
/* this funcion fills the list of short headers taken the data from
|
116
|
+
* common_headers array.
|
117
|
+
*/
|
118
|
+
static void init_short_headers(void)
|
119
|
+
{
|
120
|
+
TRACE();
|
121
|
+
int i, j;
|
122
|
+
struct common_header_name *cf = common_headers;
|
123
|
+
|
124
|
+
for(i = ARRAY_SIZE(common_headers), j=0; --i >= 0; cf++) {
|
125
|
+
if (cf->short_name != ' ') {
|
126
|
+
short_headers[j].abbr = cf->short_name;
|
127
|
+
short_headers[j].value = cf->value;
|
128
|
+
j++;
|
129
|
+
}
|
130
|
+
}
|
131
|
+
}
|
132
|
+
|
133
|
+
/* this function is called for every header set */
|
134
|
+
static VALUE find_common_header_name(const char *name, size_t len)
|
135
|
+
{
|
136
|
+
TRACE();
|
137
|
+
int i;
|
138
|
+
struct common_header_name *cf = common_headers;
|
139
|
+
|
140
|
+
for(i = ARRAY_SIZE(common_headers); --i >= 0; cf++) {
|
141
|
+
if (cf->len == (long)len && !strncasecmp(cf->name, name, len))
|
142
|
+
return cf->value;
|
143
|
+
}
|
144
|
+
return Qnil;
|
145
|
+
}
|
146
|
+
|
147
|
+
/* This function is called for every short header found */
|
148
|
+
static VALUE find_short_header_name(char abbr)
|
149
|
+
{
|
150
|
+
TRACE();
|
151
|
+
int i;
|
152
|
+
struct short_header *sh = short_headers;
|
153
|
+
|
154
|
+
for(i = ARRAY_SIZE(short_headers); --i >= 0; sh++) {
|
155
|
+
if (sh->abbr == toupper(abbr))
|
156
|
+
return sh->value;
|
157
|
+
}
|
158
|
+
return Qnil;
|
159
|
+
}
|
160
|
+
|
161
|
+
|
162
|
+
/* Tries to lookup the header name in a list of well-known headers. If so,
|
163
|
+
* returns the retrieved VALUE. It also works for short headers.
|
164
|
+
* In case the header is unknown, it normalizes it (by capitalizing the
|
165
|
+
* first letter and each letter under a "-" or "_" symbol).
|
166
|
+
*/
|
167
|
+
static VALUE headerize(const char* hname, size_t hname_len)
|
168
|
+
{
|
169
|
+
TRACE();
|
170
|
+
VALUE headerized;
|
171
|
+
char* str;
|
172
|
+
int i;
|
173
|
+
|
174
|
+
/* Header short name. */
|
175
|
+
if (hname_len == 1) {
|
176
|
+
headerized = find_short_header_name(hname[0]);
|
177
|
+
if (NIL_P(headerized)) {
|
178
|
+
headerized = rb_str_new(hname, hname_len);
|
179
|
+
/* Downcase the header name. */
|
180
|
+
downcase_char(RSTRING_PTR(headerized));
|
181
|
+
}
|
182
|
+
}
|
183
|
+
|
184
|
+
/* Header long name. */
|
185
|
+
else {
|
186
|
+
headerized = find_common_header_name(hname, hname_len);
|
187
|
+
if (NIL_P(headerized)) {
|
188
|
+
headerized = rb_str_new(hname, hname_len);
|
189
|
+
str = RSTRING_PTR(headerized);
|
190
|
+
if (*str >= 'a' && *str <= 'z')
|
191
|
+
*str &= ~0x20;
|
192
|
+
|
193
|
+
for(i = 1; i < hname_len; i++) {
|
194
|
+
if (str[i-1] == '-' || str[i-1] == '_') {
|
195
|
+
if (str[i] >= 'a' && str[i] <= 'z')
|
196
|
+
str[i] &= ~0x20;
|
197
|
+
}
|
198
|
+
else {
|
199
|
+
if (str[i] >= 'A' && str[i] <= 'Z')
|
200
|
+
str[i] += 32;
|
201
|
+
}
|
202
|
+
}
|
203
|
+
}
|
204
|
+
}
|
205
|
+
|
206
|
+
return(headerized);
|
207
|
+
}
|
208
|
+
|
209
|
+
|
210
|
+
#endif
|
@@ -0,0 +1,18 @@
|
|
1
|
+
#ifndef ext_help_h
|
2
|
+
#define ext_help_h
|
3
|
+
|
4
|
+
#define RAISE_NOT_NULL(T) if(T == NULL) rb_raise(rb_eArgError, "NULL found for " # T " when shouldn't be.");
|
5
|
+
#define DATA_GET(from,type,name) Data_Get_Struct(from,type,name); RAISE_NOT_NULL(name);
|
6
|
+
#define REQUIRE_TYPE(V, T) if(TYPE(V) != T) rb_raise(rb_eTypeError, "Wrong argument type for " # V " required " # T);
|
7
|
+
|
8
|
+
|
9
|
+
/* Uncomment for enabling TRACE() function. */
|
10
|
+
/*#define DEBUG */
|
11
|
+
|
12
|
+
#ifdef DEBUG
|
13
|
+
#define TRACE() fprintf(stderr, "TRACE: %s:%d:%s\n", __FILE__, __LINE__, __FUNCTION__)
|
14
|
+
#else
|
15
|
+
#define TRACE()
|
16
|
+
#endif
|
17
|
+
|
18
|
+
#endif
|