From 64106c4d3d4ddba8c7bc2af75376e6d3d3d75601 Mon Sep 17 00:00:00 2001
From:
Date: Mon, 29 Jun 2015 20:16:15 +0000
Subject: Update documentation
---
src/openssl/ssl/error.rs.html | 373 ++++++++
src/openssl/ssl/mod.rs.html | 2079 +++++++++++++++++++++++++++++++++++++++++
2 files changed, 2452 insertions(+)
create mode 100644 src/openssl/ssl/error.rs.html
create mode 100644 src/openssl/ssl/mod.rs.html
(limited to 'src/openssl/ssl')
diff --git a/src/openssl/ssl/error.rs.html b/src/openssl/ssl/error.rs.html
new file mode 100644
index 0000000..683c375
--- /dev/null
+++ b/src/openssl/ssl/error.rs.html
@@ -0,0 +1,373 @@
+
+
+
+ 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+
+pub use self::SslError::*;
+pub use self::OpensslError::*;
+
+use libc::c_ulong;
+use std::error;
+use std::fmt;
+use std::ffi::CStr;
+use std::io;
+
+use ffi;
+
+
+#[derive(Debug)]
+pub enum SslError {
+
+ StreamError(io::Error),
+
+ SslSessionClosed,
+
+ OpenSslErrors(Vec<OpensslError>)
+}
+
+impl fmt::Display for SslError {
+ fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
+ try!(fmt.write_str(error::Error::description(self)));
+ if let OpenSslErrors(ref errs) = *self {
+ let mut first = true;
+ for err in errs {
+ if first {
+ try!(fmt.write_str(": "));
+ first = false;
+ } else {
+ try!(fmt.write_str(", "));
+ }
+ match *err {
+ UnknownError { ref reason, .. } => try!(fmt.write_str(reason)),
+ }
+ }
+ }
+
+ Ok(())
+ }
+}
+
+impl error::Error for SslError {
+ fn description(&self) -> &str {
+ match *self {
+ StreamError(_) => "The underlying stream reported an error",
+ SslSessionClosed => "The SSL session has been closed by the other end",
+ OpenSslErrors(_) => "An error in the OpenSSL library",
+ }
+ }
+
+ fn cause(&self) -> Option<&error::Error> {
+ match *self {
+ StreamError(ref err) => Some(err as &error::Error),
+ _ => None
+ }
+ }
+}
+
+
+#[derive(Debug, Clone, PartialEq, Eq)]
+pub enum OpensslError {
+
+ UnknownError {
+
+ library: String,
+
+ function: String,
+
+ reason: String
+ }
+}
+
+fn get_lib(err: c_ulong) -> String {
+ unsafe {
+ let bytes = CStr::from_ptr(ffi::ERR_lib_error_string(err)).to_bytes().to_vec();
+ String::from_utf8(bytes).unwrap()
+ }
+}
+
+fn get_func(err: c_ulong) -> String {
+ unsafe {
+ let bytes = CStr::from_ptr(ffi::ERR_func_error_string(err)).to_bytes().to_vec();
+ String::from_utf8(bytes).unwrap()
+ }
+}
+
+fn get_reason(err: c_ulong) -> String {
+ unsafe {
+ let bytes = CStr::from_ptr(ffi::ERR_reason_error_string(err)).to_bytes().to_vec();
+ String::from_utf8(bytes).unwrap()
+ }
+}
+
+impl SslError {
+
+
+ pub fn get() -> SslError {
+ let mut errs = vec!();
+ loop {
+ match unsafe { ffi::ERR_get_error() } {
+ 0 => break,
+ err => errs.push(SslError::from_error_code(err))
+ }
+ }
+ OpenSslErrors(errs)
+ }
+
+
+ pub fn from_error(err: c_ulong) -> SslError {
+ OpenSslErrors(vec![SslError::from_error_code(err)])
+ }
+
+ fn from_error_code(err: c_ulong) -> OpensslError {
+ ffi::init();
+ UnknownError {
+ library: get_lib(err),
+ function: get_func(err),
+ reason: get_reason(err)
+ }
+ }
+}
+
+#[test]
+fn test_uknown_error_should_have_correct_messages() {
+ let errs = match SslError::from_error(336032784) {
+ OpenSslErrors(errs) => errs,
+ _ => panic!("This should always be an `OpenSslErrors` variant.")
+ };
+
+ let UnknownError { ref library, ref function, ref reason } = errs[0];
+
+ assert_eq!(&library[..], "SSL routines");
+ assert_eq!(&function[..], "SSL23_GET_SERVER_HELLO");
+ assert_eq!(&reason[..], "sslv3 alert handshake failure");
+}
+
+
+ 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+294
+295
+296
+297
+298
+299
+300
+301
+302
+303
+304
+305
+306
+307
+308
+309
+310
+311
+312
+313
+314
+315
+316
+317
+318
+319
+320
+321
+322
+323
+324
+325
+326
+327
+328
+329
+330
+331
+332
+333
+334
+335
+336
+337
+338
+339
+340
+341
+342
+343
+344
+345
+346
+347
+348
+349
+350
+351
+352
+353
+354
+355
+356
+357
+358
+359
+360
+361
+362
+363
+364
+365
+366
+367
+368
+369
+370
+371
+372
+373
+374
+375
+376
+377
+378
+379
+380
+381
+382
+383
+384
+385
+386
+387
+388
+389
+390
+391
+392
+393
+394
+395
+396
+397
+398
+399
+400
+401
+402
+403
+404
+405
+406
+407
+408
+409
+410
+411
+412
+413
+414
+415
+416
+417
+418
+419
+420
+421
+422
+423
+424
+425
+426
+427
+428
+429
+430
+431
+432
+433
+434
+435
+436
+437
+438
+439
+440
+441
+442
+443
+444
+445
+446
+447
+448
+449
+450
+451
+452
+453
+454
+455
+456
+457
+458
+459
+460
+461
+462
+463
+464
+465
+466
+467
+468
+469
+470
+471
+472
+473
+474
+475
+476
+477
+478
+479
+480
+481
+482
+483
+484
+485
+486
+487
+488
+489
+490
+491
+492
+493
+494
+495
+496
+497
+498
+499
+500
+501
+502
+503
+504
+505
+506
+507
+508
+509
+510
+511
+512
+513
+514
+515
+516
+517
+518
+519
+520
+521
+522
+523
+524
+525
+526
+527
+528
+529
+530
+531
+532
+533
+534
+535
+536
+537
+538
+539
+540
+541
+542
+543
+544
+545
+546
+547
+548
+549
+550
+551
+552
+553
+554
+555
+556
+557
+558
+559
+560
+561
+562
+563
+564
+565
+566
+567
+568
+569
+570
+571
+572
+573
+574
+575
+576
+577
+578
+579
+580
+581
+582
+583
+584
+585
+586
+587
+588
+589
+590
+591
+592
+593
+594
+595
+596
+597
+598
+599
+600
+601
+602
+603
+604
+605
+606
+607
+608
+609
+610
+611
+612
+613
+614
+615
+616
+617
+618
+619
+620
+621
+622
+623
+624
+625
+626
+627
+628
+629
+630
+631
+632
+633
+634
+635
+636
+637
+638
+639
+640
+641
+642
+643
+644
+645
+646
+647
+648
+649
+650
+651
+652
+653
+654
+655
+656
+657
+658
+659
+660
+661
+662
+663
+664
+665
+666
+667
+668
+669
+670
+671
+672
+673
+674
+675
+676
+677
+678
+679
+680
+681
+682
+683
+684
+685
+686
+687
+688
+689
+690
+691
+692
+693
+694
+695
+696
+697
+698
+699
+700
+701
+702
+703
+704
+705
+706
+707
+708
+709
+710
+711
+712
+713
+714
+715
+716
+717
+718
+719
+720
+721
+722
+723
+724
+725
+726
+727
+728
+729
+730
+731
+732
+733
+734
+735
+736
+737
+738
+739
+740
+741
+742
+743
+744
+745
+746
+747
+748
+749
+750
+751
+752
+753
+754
+755
+756
+757
+758
+759
+760
+761
+762
+763
+764
+765
+766
+767
+768
+769
+770
+771
+772
+773
+774
+775
+776
+777
+778
+779
+780
+781
+782
+783
+784
+785
+786
+787
+788
+789
+790
+791
+792
+793
+794
+795
+796
+797
+798
+799
+800
+801
+802
+803
+804
+805
+806
+807
+808
+809
+810
+811
+812
+813
+814
+815
+816
+817
+818
+819
+820
+821
+822
+823
+824
+825
+826
+827
+828
+829
+830
+831
+832
+833
+834
+835
+836
+837
+838
+839
+840
+841
+842
+843
+844
+845
+846
+847
+848
+849
+850
+851
+852
+853
+854
+855
+856
+857
+858
+859
+860
+861
+862
+863
+864
+865
+866
+867
+868
+869
+870
+871
+872
+873
+874
+875
+876
+877
+878
+879
+880
+881
+882
+883
+884
+885
+886
+887
+888
+889
+890
+891
+892
+893
+894
+895
+896
+897
+898
+899
+900
+901
+902
+903
+904
+905
+906
+907
+908
+909
+910
+911
+912
+913
+914
+915
+916
+917
+918
+919
+920
+921
+922
+923
+924
+925
+926
+927
+928
+929
+930
+931
+932
+933
+934
+935
+936
+937
+938
+939
+940
+941
+942
+943
+944
+945
+946
+947
+948
+949
+950
+951
+952
+953
+954
+955
+956
+957
+958
+959
+960
+961
+962
+963
+964
+965
+966
+967
+968
+969
+970
+971
+972
+973
+974
+975
+976
+977
+978
+979
+980
+981
+982
+983
+984
+985
+986
+987
+988
+989
+990
+991
+
+use libc::{c_int, c_void, c_long};
+use std::any::TypeId;
+use std::collections::HashMap;
+use std::ffi::{CStr, CString};
+use std::fmt;
+use std::io;
+use std::io::prelude::*;
+use std::mem;
+use std::net;
+use std::path::Path;
+use std::ptr;
+use std::sync::{Once, ONCE_INIT, Arc, Mutex};
+use std::ops::{Deref, DerefMut};
+use std::cmp;
+use std::any::Any;
+#[cfg(feature = "npn")]
+use libc::{c_uchar, c_uint};
+#[cfg(feature = "npn")]
+use std::slice;
+
+use bio::{MemBio};
+use ffi;
+use ssl::error::{SslError, SslSessionClosed, StreamError, OpenSslErrors};
+use x509::{X509StoreContext, X509FileType, X509};
+use crypto::pkey::PKey;
+
+pub mod error;
+#[cfg(test)]
+mod tests;
+
+static mut VERIFY_IDX: c_int = -1;
+
+fn init() {
+ static mut INIT: Once = ONCE_INIT;
+
+ unsafe {
+ INIT.call_once(|| {
+ ffi::init();
+
+ let verify_idx = ffi::SSL_CTX_get_ex_new_index(0, ptr::null(), None,
+ None, None);
+ assert!(verify_idx >= 0);
+ VERIFY_IDX = verify_idx;
+ });
+ }
+}
+
+bitflags! {
+ flags SslContextOptions: c_long {
+ const SSL_OP_LEGACY_SERVER_CONNECT = 0x00000004,
+ const SSL_OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG = 0x00000008,
+ const SSL_OP_TLSEXT_PADDING = 0x00000010,
+ const SSL_OP_MICROSOFT_BIG_SSLV3_BUFFER = 0x00000020,
+ const SSL_OP_SAFARI_ECDHE_ECDSA_BUG = 0x00000040,
+ const SSL_OP_SSLEAY_080_CLIENT_DH_BUG = 0x00000080,
+ const SSL_OP_TLS_D5_BUG = 0x00000100,
+ const SSL_OP_TLS_BLOCK_PADDING_BUG = 0x00000200,
+ const SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS = 0x00000800,
+ const SSL_OP_ALL = 0x80000BFF,
+ const SSL_OP_NO_QUERY_MTU = 0x00001000,
+ const SSL_OP_COOKIE_EXCHANGE = 0x00002000,
+ const SSL_OP_NO_TICKET = 0x00004000,
+ const SSL_OP_CISCO_ANYCONNECT = 0x00008000,
+ const SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION = 0x00010000,
+ const SSL_OP_NO_COMPRESSION = 0x00020000,
+ const SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION = 0x00040000,
+ const SSL_OP_SINGLE_ECDH_USE = 0x00080000,
+ const SSL_OP_SINGLE_DH_USE = 0x00100000,
+ const SSL_OP_CIPHER_SERVER_PREFERENCE = 0x00400000,
+ const SSL_OP_TLS_ROLLBACK_BUG = 0x00800000,
+ const SSL_OP_NO_SSLV2 = 0x00000000,
+ const SSL_OP_NO_SSLV3 = 0x02000000,
+ const SSL_OP_NO_TLSV1 = 0x04000000,
+ const SSL_OP_NO_TLSV1_2 = 0x08000000,
+ const SSL_OP_NO_TLSV1_1 = 0x10000000,
+ const SSL_OP_NO_DTLSV1 = 0x04000000,
+ const SSL_OP_NO_DTLSV1_2 = 0x08000000
+ }
+}
+
+
+#[allow(non_camel_case_types)]
+#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
+pub enum SslMethod {
+ #[cfg(feature = "sslv2")]
+
+ Sslv2,
+
+ Sslv23,
+
+ Sslv3,
+
+ Tlsv1,
+ #[cfg(feature = "tlsv1_1")]
+
+ Tlsv1_1,
+ #[cfg(feature = "tlsv1_2")]
+
+ Tlsv1_2,
+ #[cfg(feature = "dtlsv1")]
+
+ Dtlsv1,
+ #[cfg(feature = "dtlsv1_2")]
+
+ Dtlsv1_2,
+}
+
+impl SslMethod {
+ unsafe fn to_raw(&self) -> *const ffi::SSL_METHOD {
+ match *self {
+ #[cfg(feature = "sslv2")]
+ SslMethod::Sslv2 => ffi::SSLv2_method(),
+ SslMethod::Sslv3 => ffi::SSLv3_method(),
+ SslMethod::Tlsv1 => ffi::TLSv1_method(),
+ SslMethod::Sslv23 => ffi::SSLv23_method(),
+ #[cfg(feature = "tlsv1_1")]
+ SslMethod::Tlsv1_1 => ffi::TLSv1_1_method(),
+ #[cfg(feature = "tlsv1_2")]
+ SslMethod::Tlsv1_2 => ffi::TLSv1_2_method(),
+ #[cfg(feature = "dtlsv1")]
+ SslMethod::Dtlsv1 => ffi::DTLSv1_method(),
+ #[cfg(feature = "dtlsv1_2")]
+ SslMethod::Dtlsv1_2 => ffi::DTLSv1_2_method(),
+ }
+ }
+
+ #[cfg(feature = "dtlsv1")]
+ pub fn is_dtlsv1(&self) -> bool {
+ *self == SslMethod::Dtlsv1
+ }
+
+ #[cfg(feature = "dtlsv1_2")]
+ pub fn is_dtlsv1_2(&self) -> bool {
+ *self == SslMethod::Dtlsv1_2
+ }
+
+ pub fn is_dtls(&self) -> bool {
+ self.is_dtlsv1() || self.is_dtlsv1_2()
+ }
+
+ #[cfg(not(feature = "dtlsv1"))]
+ pub fn is_dtlsv1(&self) -> bool {
+ false
+ }
+
+ #[cfg(not(feature = "dtlsv1_2"))]
+ pub fn is_dtlsv1_2(&self) -> bool {
+ false
+ }
+}
+
+
+bitflags! {
+ flags SslVerifyMode: i32 {
+
+ const SSL_VERIFY_PEER = ffi::SSL_VERIFY_PEER,
+
+ const SSL_VERIFY_NONE = ffi::SSL_VERIFY_NONE,
+
+
+ const SSL_VERIFY_FAIL_IF_NO_PEER_CERT = ffi::SSL_VERIFY_FAIL_IF_NO_PEER_CERT,
+ }
+}
+
+lazy_static! {
+ static ref INDEXES: Mutex<HashMap<TypeId, c_int>> = Mutex::new(HashMap::new());
+}
+
+
+
+
+fn get_verify_data_idx<T: Any + 'static>() -> c_int {
+ extern fn free_data_box<T>(_parent: *mut c_void, ptr: *mut c_void,
+ _ad: *mut ffi::CRYPTO_EX_DATA, _idx: c_int,
+ _argl: c_long, _argp: *mut c_void) {
+ if ptr != 0 as *mut _ {
+ let _: Box<T> = unsafe { mem::transmute(ptr) };
+ }
+ }
+
+ *INDEXES.lock().unwrap().entry(TypeId::of::<T>()).or_insert_with(|| {
+ unsafe {
+ let f: ffi::CRYPTO_EX_free = free_data_box::<T>;
+ let idx = ffi::SSL_CTX_get_ex_new_index(0, ptr::null(), None, None, Some(f));
+ assert!(idx >= 0);
+ idx
+ }
+ })
+}
+
+
+
+
+#[cfg(feature = "npn")]
+fn get_npn_protos_idx() -> c_int {
+ static mut NPN_PROTOS_IDX: c_int = -1;
+ static mut INIT: Once = ONCE_INIT;
+
+ extern fn free_data_box(_parent: *mut c_void, ptr: *mut c_void,
+ _ad: *mut ffi::CRYPTO_EX_DATA, _idx: c_int,
+ _argl: c_long, _argp: *mut c_void) {
+ if !ptr.is_null() {
+ let _: Box<Vec<u8>> = unsafe { mem::transmute(ptr) };
+ }
+ }
+
+ unsafe {
+ INIT.call_once(|| {
+ let f: ffi::CRYPTO_EX_free = free_data_box;
+ let idx = ffi::SSL_CTX_get_ex_new_index(0, ptr::null(), None,
+ None, Some(f));
+ assert!(idx >= 0);
+ NPN_PROTOS_IDX = idx;
+ });
+ NPN_PROTOS_IDX
+ }
+}
+
+extern fn raw_verify(preverify_ok: c_int, x509_ctx: *mut ffi::X509_STORE_CTX)
+ -> c_int {
+ unsafe {
+ let idx = ffi::SSL_get_ex_data_X509_STORE_CTX_idx();
+ let ssl = ffi::X509_STORE_CTX_get_ex_data(x509_ctx, idx);
+ let ssl_ctx = ffi::SSL_get_SSL_CTX(ssl);
+ let verify = ffi::SSL_CTX_get_ex_data(ssl_ctx, VERIFY_IDX);
+ let verify: Option<VerifyCallback> = mem::transmute(verify);
+
+ let ctx = X509StoreContext::new(x509_ctx);
+
+ match verify {
+ None => preverify_ok,
+ Some(verify) => verify(preverify_ok != 0, &ctx) as c_int
+ }
+ }
+}
+
+extern fn raw_verify_with_data<T>(preverify_ok: c_int,
+ x509_ctx: *mut ffi::X509_STORE_CTX) -> c_int
+ where T: Any + 'static {
+ unsafe {
+ let idx = ffi::SSL_get_ex_data_X509_STORE_CTX_idx();
+ let ssl = ffi::X509_STORE_CTX_get_ex_data(x509_ctx, idx);
+ let ssl_ctx = ffi::SSL_get_SSL_CTX(ssl);
+
+ let verify = ffi::SSL_CTX_get_ex_data(ssl_ctx, VERIFY_IDX);
+ let verify: Option<VerifyCallbackData<T>> = mem::transmute(verify);
+
+ let data = ffi::SSL_CTX_get_ex_data(ssl_ctx, get_verify_data_idx::<T>());
+ let data: Box<T> = mem::transmute(data);
+
+ let ctx = X509StoreContext::new(x509_ctx);
+
+ let res = match verify {
+ None => preverify_ok,
+ Some(verify) => verify(preverify_ok != 0, &ctx, &*data) as c_int
+ };
+
+
+
+
+
+ mem::forget(data);
+ res
+ }
+}
+
+
+
+
+
+
+
+#[cfg(feature = "npn")]
+extern fn raw_next_proto_select_cb(ssl: *mut ffi::SSL,
+ out: *mut *mut c_uchar, outlen: *mut c_uchar,
+ inbuf: *const c_uchar, inlen: c_uint,
+ _arg: *mut c_void) -> c_int {
+ unsafe {
+
+
+ let ssl_ctx = ffi::SSL_get_SSL_CTX(ssl);
+ let protocols = ffi::SSL_CTX_get_ex_data(ssl_ctx, get_npn_protos_idx());
+ let protocols: &Vec<u8> = mem::transmute(protocols);
+
+ let client = protocols.as_ptr();
+ let client_len = protocols.len() as c_uint;
+
+
+ ffi::SSL_select_next_proto(out, outlen, inbuf, inlen, client, client_len);
+ }
+
+ ffi::SSL_TLSEXT_ERR_OK
+}
+
+
+
+
+
+
+
+
+#[cfg(feature = "npn")]
+extern fn raw_next_protos_advertise_cb(ssl: *mut ffi::SSL,
+ out: *mut *const c_uchar, outlen: *mut c_uint,
+ _arg: *mut c_void) -> c_int {
+ unsafe {
+
+ let ssl_ctx = ffi::SSL_get_SSL_CTX(ssl);
+ let protocols = ffi::SSL_CTX_get_ex_data(ssl_ctx, get_npn_protos_idx());
+ if protocols.is_null() {
+ *out = b"".as_ptr();
+ *outlen = 0;
+ } else {
+
+
+ let protocols: &Vec<u8> = mem::transmute(protocols);
+ *out = protocols.as_ptr();
+ *outlen = protocols.len() as c_uint;
+ }
+ }
+
+ ffi::SSL_TLSEXT_ERR_OK
+}
+
+
+pub type VerifyCallback = fn(preverify_ok: bool,
+ x509_ctx: &X509StoreContext) -> bool;
+
+
+
+pub type VerifyCallbackData<T> = fn(preverify_ok: bool,
+ x509_ctx: &X509StoreContext,
+ data: &T) -> bool;
+
+
+#[inline]
+fn wrap_ssl_result(res: c_int) -> Result<(),SslError> {
+ if res == 0 {
+ Err(SslError::get())
+ } else {
+ Ok(())
+ }
+}
+
+
+pub struct SslContext {
+ ctx: *mut ffi::SSL_CTX
+}
+
+unsafe impl Send for SslContext {}
+unsafe impl Sync for SslContext {}
+
+
+impl fmt::Debug for SslContext {
+ fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
+ write!(fmt, "SslContext")
+ }
+}
+
+impl Drop for SslContext {
+ fn drop(&mut self) {
+ unsafe { ffi::SSL_CTX_free(self.ctx) }
+ }
+}
+
+impl SslContext {
+
+ pub fn new(method: SslMethod) -> Result<SslContext, SslError> {
+ init();
+
+ let ctx = unsafe { ffi::SSL_CTX_new(method.to_raw()) };
+ if ctx == ptr::null_mut() {
+ return Err(SslError::get());
+ }
+
+ let ctx = SslContext { ctx: ctx };
+
+ if method.is_dtls() {
+ ctx.set_read_ahead(1);
+ }
+
+ Ok(ctx)
+ }
+
+
+ pub fn set_verify(&mut self, mode: SslVerifyMode,
+ verify: Option<VerifyCallback>) {
+ unsafe {
+ ffi::SSL_CTX_set_ex_data(self.ctx, VERIFY_IDX,
+ mem::transmute(verify));
+ let f: extern fn(c_int, *mut ffi::X509_STORE_CTX) -> c_int =
+ raw_verify;
+
+ ffi::SSL_CTX_set_verify(self.ctx, mode.bits as c_int, Some(f));
+ }
+ }
+
+
+
+
+
+ pub fn set_verify_with_data<T>(&mut self, mode: SslVerifyMode,
+ verify: VerifyCallbackData<T>,
+ data: T)
+ where T: Any + 'static {
+ let data = Box::new(data);
+ unsafe {
+ ffi::SSL_CTX_set_ex_data(self.ctx, VERIFY_IDX,
+ mem::transmute(Some(verify)));
+ ffi::SSL_CTX_set_ex_data(self.ctx, get_verify_data_idx::<T>(),
+ mem::transmute(data));
+ let f: extern fn(c_int, *mut ffi::X509_STORE_CTX) -> c_int =
+ raw_verify_with_data::<T>;
+
+ ffi::SSL_CTX_set_verify(self.ctx, mode.bits as c_int, Some(f));
+ }
+ }
+
+
+ pub fn set_verify_depth(&mut self, depth: u32) {
+ unsafe {
+ ffi::SSL_CTX_set_verify_depth(self.ctx, depth as c_int);
+ }
+ }
+
+ pub fn set_read_ahead(&self, m: u32) {
+ unsafe {
+ ffi::SSL_CTX_set_read_ahead(self.ctx, m as c_long);
+ }
+ }
+
+ #[allow(non_snake_case)]
+
+ pub fn set_CA_file<P: AsRef<Path>>(&mut self, file: P) -> Result<(),SslError> {
+ let file = CString::new(file.as_ref().as_os_str().to_str().expect("invalid utf8")).unwrap();
+ wrap_ssl_result(
+ unsafe {
+ ffi::SSL_CTX_load_verify_locations(self.ctx, file.as_ptr(), ptr::null())
+ })
+ }
+
+
+ pub fn set_certificate_file<P: AsRef<Path>>(&mut self, file: P, file_type: X509FileType)
+ -> Result<(),SslError> {
+ let file = CString::new(file.as_ref().as_os_str().to_str().expect("invalid utf8")).unwrap();
+ wrap_ssl_result(
+ unsafe {
+ ffi::SSL_CTX_use_certificate_file(self.ctx, file.as_ptr(), file_type as c_int)
+ })
+ }
+
+
+ pub fn set_certificate(&mut self, cert: &X509) -> Result<(),SslError> {
+ wrap_ssl_result(
+ unsafe {
+ ffi::SSL_CTX_use_certificate(self.ctx, cert.get_handle())
+ })
+ }
+
+
+
+ pub fn add_extra_chain_cert(&mut self, cert: &X509) -> Result<(),SslError> {
+ wrap_ssl_result(
+ unsafe {
+ ffi::SSL_CTX_add_extra_chain_cert(self.ctx, cert.get_handle()) as c_int
+ })
+ }
+
+
+ pub fn set_private_key_file<P: AsRef<Path>>(&mut self, file: P,
+ file_type: X509FileType) -> Result<(),SslError> {
+ let file = CString::new(file.as_ref().as_os_str().to_str().expect("invalid utf8")).unwrap();
+ wrap_ssl_result(
+ unsafe {
+ ffi::SSL_CTX_use_PrivateKey_file(self.ctx, file.as_ptr(), file_type as c_int)
+ })
+ }
+
+
+ pub fn set_private_key(&mut self, key: &PKey) -> Result<(),SslError> {
+ wrap_ssl_result(
+ unsafe {
+ ffi::SSL_CTX_use_PrivateKey(self.ctx, key.get_handle())
+ })
+ }
+
+
+ pub fn check_private_key(&mut self) -> Result<(),SslError> {
+ wrap_ssl_result(
+ unsafe {
+ ffi::SSL_CTX_check_private_key(self.ctx)
+ })
+ }
+
+ pub fn set_cipher_list(&mut self, cipher_list: &str) -> Result<(),SslError> {
+ wrap_ssl_result(
+ unsafe {
+ let cipher_list = CString::new(cipher_list.as_bytes()).unwrap();
+ ffi::SSL_CTX_set_cipher_list(self.ctx, cipher_list.as_ptr())
+ })
+ }
+
+ pub fn set_options(&mut self, option: SslContextOptions) -> SslContextOptions {
+ let raw_bits = option.bits();
+ let ret = unsafe {
+ ffi::SSL_CTX_set_options(self.ctx, raw_bits)
+ };
+ SslContextOptions::from_bits(ret).unwrap()
+ }
+
+ pub fn get_options(&mut self) -> SslContextOptions {
+ let ret = unsafe {
+ ffi::SSL_CTX_get_options(self.ctx)
+ };
+ SslContextOptions::from_bits(ret).unwrap()
+ }
+
+ pub fn clear_options(&mut self, option: SslContextOptions) -> SslContextOptions {
+ let raw_bits = option.bits();
+ let ret = unsafe {
+ ffi::SSL_CTX_clear_options(self.ctx, raw_bits)
+ };
+ SslContextOptions::from_bits(ret).unwrap()
+ }
+
+
+
+
+
+ #[cfg(feature = "npn")]
+ pub fn set_npn_protocols(&mut self, protocols: &[&[u8]]) {
+
+
+ let mut npn_protocols = Vec::new();
+ for protocol in protocols {
+ let len = protocol.len() as u8;
+ npn_protocols.push(len);
+
+ npn_protocols.extend(protocol[..len as usize].to_vec());
+ }
+ let protocols: Box<Vec<u8>> = Box::new(npn_protocols);
+
+ unsafe {
+
+
+ ffi::SSL_CTX_set_ex_data(self.ctx, get_npn_protos_idx(),
+ mem::transmute(protocols));
+
+
+
+ ffi::SSL_CTX_set_next_proto_select_cb(self.ctx, raw_next_proto_select_cb, ptr::null_mut());
+
+
+ ffi::SSL_CTX_set_next_protos_advertised_cb(self.ctx, raw_next_protos_advertise_cb, ptr::null_mut());
+ }
+ }
+}
+
+#[allow(dead_code)]
+struct MemBioRef<'ssl> {
+ ssl: &'ssl Ssl,
+ bio: MemBio,
+}
+
+impl<'ssl> Deref for MemBioRef<'ssl> {
+ type Target = MemBio;
+
+ fn deref(&self) -> &MemBio {
+ &self.bio
+ }
+}
+
+impl<'ssl> DerefMut for MemBioRef<'ssl> {
+ fn deref_mut(&mut self) -> &mut MemBio {
+ &mut self.bio
+ }
+}
+
+pub struct Ssl {
+ ssl: *mut ffi::SSL
+}
+
+unsafe impl Send for Ssl {}
+unsafe impl Sync for Ssl {}
+
+
+impl fmt::Debug for Ssl {
+ fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
+ write!(fmt, "Ssl")
+ }
+}
+
+impl Drop for Ssl {
+ fn drop(&mut self) {
+ unsafe { ffi::SSL_free(self.ssl) }
+ }
+}
+
+impl Ssl {
+ pub fn new(ctx: &SslContext) -> Result<Ssl, SslError> {
+ let ssl = unsafe { ffi::SSL_new(ctx.ctx) };
+ if ssl == ptr::null_mut() {
+ return Err(SslError::get());
+ }
+ let ssl = Ssl { ssl: ssl };
+
+ let rbio = try!(MemBio::new());
+ let wbio = try!(MemBio::new());
+
+ unsafe { ffi::SSL_set_bio(ssl.ssl, rbio.unwrap(), wbio.unwrap()) }
+ Ok(ssl)
+ }
+
+ fn get_rbio<'a>(&'a self) -> MemBioRef<'a> {
+ unsafe { self.wrap_bio(ffi::SSL_get_rbio(self.ssl)) }
+ }
+
+ fn get_wbio<'a>(&'a self) -> MemBioRef<'a> {
+ unsafe { self.wrap_bio(ffi::SSL_get_wbio(self.ssl)) }
+ }
+
+ fn wrap_bio<'a>(&'a self, bio: *mut ffi::BIO) -> MemBioRef<'a> {
+ assert!(bio != ptr::null_mut());
+ MemBioRef {
+ ssl: self,
+ bio: MemBio::borrowed(bio)
+ }
+ }
+
+ fn connect(&self) -> c_int {
+ unsafe { ffi::SSL_connect(self.ssl) }
+ }
+
+ fn accept(&self) -> c_int {
+ unsafe { ffi::SSL_accept(self.ssl) }
+ }
+
+ fn read(&self, buf: &mut [u8]) -> c_int {
+ let len = cmp::min(c_int::max_value() as usize, buf.len()) as c_int;
+ unsafe { ffi::SSL_read(self.ssl, buf.as_ptr() as *mut c_void, len) }
+ }
+
+ fn write(&self, buf: &[u8]) -> c_int {
+ let len = cmp::min(c_int::max_value() as usize, buf.len()) as c_int;
+ unsafe { ffi::SSL_write(self.ssl, buf.as_ptr() as *const c_void, len) }
+ }
+
+ fn get_error(&self, ret: c_int) -> LibSslError {
+ let err = unsafe { ffi::SSL_get_error(self.ssl, ret) };
+ match LibSslError::from_i32(err as i32) {
+ Some(err) => err,
+ None => unreachable!()
+ }
+ }
+
+
+ pub fn set_hostname(&self, hostname: &str) -> Result<(), SslError> {
+ let ret = unsafe {
+
+
+
+
+ let hostname = CString::new(hostname.as_bytes()).unwrap();
+ ffi::SSL_ctrl(self.ssl, ffi::SSL_CTRL_SET_TLSEXT_HOSTNAME,
+ ffi::TLSEXT_NAMETYPE_host_name,
+ hostname.as_ptr() as *mut c_void)
+ };
+
+
+ if ret == 0 {
+ Err(SslError::get())
+ } else {
+ Ok(())
+ }
+ }
+
+ pub fn get_peer_certificate(&self) -> Option<X509> {
+ unsafe {
+ let ptr = ffi::SSL_get_peer_certificate(self.ssl);
+ if ptr.is_null() {
+ None
+ } else {
+ Some(X509::new(ptr, true))
+ }
+ }
+ }
+
+
+
+
+
+
+
+ #[cfg(feature = "npn")]
+ pub fn get_selected_npn_protocol(&self) -> Option<&[u8]> {
+ unsafe {
+ let mut data: *const c_uchar = ptr::null();
+ let mut len: c_uint = 0;
+
+
+ ffi::SSL_get0_next_proto_negotiated(self.ssl, &mut data, &mut len);
+
+ if data.is_null() {
+ None
+ } else {
+ Some(slice::from_raw_parts(data, len as usize))
+ }
+ }
+ }
+
+
+ pub fn pending(&self) -> usize {
+ unsafe {
+ ffi::SSL_pending(self.ssl) as usize
+ }
+ }
+}
+
+macro_rules! make_LibSslError {
+ ($($variant:ident = $value:ident),+) => {
+ #[derive(Debug)]
+ #[repr(i32)]
+ enum LibSslError {
+ $($variant = ffi::$value),+
+ }
+
+ impl LibSslError {
+ fn from_i32(val: i32) -> Option<LibSslError> {
+ match val {
+ $(ffi::$value => Some(LibSslError::$variant),)+
+ _ => None
+ }
+ }
+ }
+ }
+}
+
+make_LibSslError! {
+ ErrorNone = SSL_ERROR_NONE,
+ ErrorSsl = SSL_ERROR_SSL,
+ ErrorWantRead = SSL_ERROR_WANT_READ,
+ ErrorWantWrite = SSL_ERROR_WANT_WRITE,
+ ErrorWantX509Lookup = SSL_ERROR_WANT_X509_LOOKUP,
+ ErrorSyscall = SSL_ERROR_SYSCALL,
+ ErrorZeroReturn = SSL_ERROR_ZERO_RETURN,
+ ErrorWantConnect = SSL_ERROR_WANT_CONNECT,
+ ErrorWantAccept = SSL_ERROR_WANT_ACCEPT
+}
+
+
+#[derive(Clone)]
+pub struct SslStream<S> {
+ stream: S,
+ ssl: Arc<Ssl>,
+ buf: Vec<u8>
+}
+
+impl SslStream<net::TcpStream> {
+
+ pub fn try_clone(&self) -> io::Result<SslStream<net::TcpStream>> {
+ Ok(SslStream {
+ stream: try!(self.stream.try_clone()),
+ ssl: self.ssl.clone(),
+ buf: self.buf.clone(),
+ })
+ }
+}
+
+impl<S> fmt::Debug for SslStream<S> where S: fmt::Debug {
+ fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
+ write!(fmt, "SslStream {{ stream: {:?}, ssl: {:?} }}", self.stream, self.ssl)
+ }
+}
+
+impl<S: Read+Write> SslStream<S> {
+ fn new_base(ssl:Ssl, stream: S) -> SslStream<S> {
+ SslStream {
+ stream: stream,
+ ssl: Arc::new(ssl),
+
+
+
+ buf: {
+ const CAP: usize = 16 * 1024;
+ let mut v = Vec::with_capacity(CAP);
+ unsafe { v.set_len(CAP); }
+ v
+ }
+ }
+ }
+
+ pub fn new_server_from(ssl: Ssl, stream: S) -> Result<SslStream<S>, SslError> {
+ let mut ssl = SslStream::new_base(ssl, stream);
+ ssl.in_retry_wrapper(|ssl| { ssl.accept() }).and(Ok(ssl))
+ }
+
+
+ pub fn new_from(ssl: Ssl, stream: S) -> Result<SslStream<S>, SslError> {
+ let mut ssl = SslStream::new_base(ssl, stream);
+ ssl.in_retry_wrapper(|ssl| { ssl.connect() }).and(Ok(ssl))
+ }
+
+
+ pub fn new(ctx: &SslContext, stream: S) -> Result<SslStream<S>, SslError> {
+ let ssl = try!(Ssl::new(ctx));
+ SslStream::new_from(ssl, stream)
+ }
+
+
+ pub fn new_server(ctx: &SslContext, stream: S) -> Result<SslStream<S>, SslError> {
+ let ssl = try!(Ssl::new(ctx));
+ SslStream::new_server_from(ssl, stream)
+ }
+
+ #[doc(hidden)]
+ pub fn get_inner(&mut self) -> &mut S {
+ self.get_mut()
+ }
+
+
+ pub fn get_ref(&self) -> &S {
+ &self.stream
+ }
+
+
+ pub fn get_peer_certificate(&self) -> Option<X509> {
+ self.ssl.get_peer_certificate()
+ }
+
+
+
+
+
+
+
+ pub fn get_mut(&mut self) -> &mut S {
+ &mut self.stream
+ }
+
+ fn in_retry_wrapper<F>(&mut self, mut blk: F)
+ -> Result<c_int, SslError> where F: FnMut(&Ssl) -> c_int {
+ loop {
+ let ret = blk(&self.ssl);
+ if ret > 0 {
+ return Ok(ret);
+ }
+
+ let e = self.ssl.get_error(ret);
+ match e {
+ LibSslError::ErrorWantRead => {
+ try_ssl_stream!(self.flush());
+ let len = try_ssl_stream!(self.stream.read(&mut self.buf[..]));
+ if len == 0 {
+ self.ssl.get_rbio().set_eof(true);
+ } else {
+ try_ssl_stream!(self.ssl.get_rbio().write_all(&self.buf[..len]));
+ }
+ }
+ LibSslError::ErrorWantWrite => { try_ssl_stream!(self.flush()) }
+ LibSslError::ErrorZeroReturn => return Err(SslSessionClosed),
+ LibSslError::ErrorSsl => return Err(SslError::get()),
+ LibSslError::ErrorSyscall if ret == 0 => return Ok(0),
+ err => panic!("unexpected error {:?} with ret {}", err, ret),
+ }
+ }
+ }
+
+ fn write_through(&mut self) -> io::Result<()> {
+ io::copy(&mut *self.ssl.get_wbio(), &mut self.stream).map(|_| ())
+ }
+
+
+
+
+ pub fn get_compression(&self) -> Option<String> {
+ let ptr = unsafe { ffi::SSL_get_current_compression(self.ssl.ssl) };
+ if ptr == ptr::null() {
+ return None;
+ }
+
+ let meth = unsafe { ffi::SSL_COMP_get_name(ptr) };
+ let s = unsafe {
+ String::from_utf8(CStr::from_ptr(meth).to_bytes().to_vec()).unwrap()
+ };
+
+ Some(s)
+ }
+
+
+
+
+
+
+
+ #[cfg(feature = "npn")]
+ pub fn get_selected_npn_protocol(&self) -> Option<&[u8]> {
+ self.ssl.get_selected_npn_protocol()
+ }
+
+
+ pub fn pending(&self) -> usize {
+ self.ssl.pending()
+ }
+}
+
+impl<S: Read+Write> Read for SslStream<S> {
+ fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
+ match self.in_retry_wrapper(|ssl| { ssl.read(buf) }) {
+ Ok(len) => Ok(len as usize),
+ Err(SslSessionClosed) => Ok(0),
+ Err(StreamError(e)) => Err(e),
+ Err(e @ OpenSslErrors(_)) => {
+ Err(io::Error::new(io::ErrorKind::Other, e))
+ }
+ }
+ }
+}
+
+impl<S: Read+Write> Write for SslStream<S> {
+ fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
+ let count = match self.in_retry_wrapper(|ssl| ssl.write(buf)) {
+ Ok(len) => len as usize,
+ Err(SslSessionClosed) => 0,
+ Err(StreamError(e)) => return Err(e),
+ Err(e @ OpenSslErrors(_)) => return Err(io::Error::new(io::ErrorKind::Other, e)),
+ };
+ try!(self.write_through());
+ Ok(count)
+ }
+
+ fn flush(&mut self) -> io::Result<()> {
+ try!(self.write_through());
+ self.stream.flush()
+ }
+}
+
+
+#[derive(Debug)]
+pub enum MaybeSslStream<S> where S: Read+Write {
+
+ Ssl(SslStream<S>),
+
+ Normal(S),
+}
+
+impl<S> Read for MaybeSslStream<S> where S: Read+Write {
+ fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
+ match *self {
+ MaybeSslStream::Ssl(ref mut s) => s.read(buf),
+ MaybeSslStream::Normal(ref mut s) => s.read(buf),
+ }
+ }
+}
+
+impl<S> Write for MaybeSslStream<S> where S: Read+Write {
+ fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
+ match *self {
+ MaybeSslStream::Ssl(ref mut s) => s.write(buf),
+ MaybeSslStream::Normal(ref mut s) => s.write(buf),
+ }
+ }
+
+ fn flush(&mut self) -> io::Result<()> {
+ match *self {
+ MaybeSslStream::Ssl(ref mut s) => s.flush(),
+ MaybeSslStream::Normal(ref mut s) => s.flush(),
+ }
+ }
+}
+
+impl<S> MaybeSslStream<S> where S: Read+Write {
+
+ pub fn get_ref(&self) -> &S {
+ match *self {
+ MaybeSslStream::Ssl(ref s) => s.get_ref(),
+ MaybeSslStream::Normal(ref s) => s,
+ }
+ }
+
+
+
+
+
+
+ pub fn get_mut(&mut self) -> &mut S {
+ match *self {
+ MaybeSslStream::Ssl(ref mut s) => s.get_mut(),
+ MaybeSslStream::Normal(ref mut s) => s,
+ }
+ }
+}
+
+
+