SSL_SESSION wrapper
[folly.git] / folly / ssl / detail / SSLSessionImpl.cpp
1 /*
2  * Copyright 2016 Facebook, Inc.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *   http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 #include <folly/ssl/detail/SSLSessionImpl.h>
18 #include <folly/ssl/detail/OpenSSLVersionFinder.h>
19
20 namespace folly {
21 namespace ssl {
22 namespace detail {
23
24 //
25 // Wrapper OpenSSL 1.0.2 (and possibly 1.0.1)
26 //
27
28 SSLSessionImpl::SSLSessionImpl(SSL_SESSION* session, bool takeOwnership)
29     : session_(session) {
30   if (session_ == nullptr) {
31     throw std::runtime_error("SSL_SESSION is null");
32   }
33   // If we're not given ownership, we need to up the refcount so the SSL_SESSION
34   // object won't be freed while SSLSessionImpl is alive
35   if (!takeOwnership) {
36     upRef();
37   }
38 }
39
40 SSLSessionImpl::SSLSessionImpl(const std::string& serializedSession) {
41   auto sessionData =
42       reinterpret_cast<const unsigned char*>(serializedSession.data());
43   if ((session_ = d2i_SSL_SESSION(
44            nullptr, &sessionData, serializedSession.length())) == nullptr) {
45     throw std::runtime_error("Cannot deserialize SSLSession string");
46   }
47 }
48
49 SSLSessionImpl::~SSLSessionImpl() {
50   downRef();
51 }
52
53 std::string SSLSessionImpl::serialize(void) const {
54   std::string ret;
55
56   // Get the length first, then we know how much space to allocate.
57   auto len = i2d_SSL_SESSION(session_, nullptr);
58
59   if (len > 0) {
60     std::unique_ptr<unsigned char[]> uptr(new unsigned char[len]);
61     auto p = uptr.get();
62     auto written = i2d_SSL_SESSION(session_, &p);
63     if (written <= 0) {
64       VLOG(2) << "Could not serialize SSL_SESSION!";
65     } else {
66       ret.assign(uptr.get(), uptr.get() + written);
67     }
68   }
69   return ret;
70 }
71
72 std::string SSLSessionImpl::getSessionID() const {
73   std::string ret;
74   if (session_) {
75     const unsigned char* ptr = nullptr;
76     unsigned int len = 0;
77 #if defined(OPENSSL_IS_102) || defined(OPENSSL_IS_101)
78     len = session_->session_id_length;
79     ptr = session_->session_id;
80 #elif defined(OPENSSL_IS_110) || defined(OPENSSL_IS_BORINGSSL)
81     ptr = SSL_SESSION_get_id(session_, &len);
82 #endif
83     ret.assign(ptr, ptr + len);
84   }
85   return ret;
86 }
87
88 const SSL_SESSION* SSLSessionImpl::getRawSSLSession() const {
89   return const_cast<SSL_SESSION*>(session_);
90 }
91
92 SSL_SESSION* SSLSessionImpl::getRawSSLSessionDangerous() {
93   upRef();
94   return session_;
95 }
96
97 void SSLSessionImpl::upRef() {
98   if (session_) {
99 #if defined(OPENSSL_IS_102) || defined(OPENSSL_IS_101)
100     CRYPTO_add(&session_->references, 1, CRYPTO_LOCK_SSL_SESSION);
101 #elif defined(OPENSSL_IS_BORINGSSL) || defined(OPENSSL_IS_110)
102     SSL_SESSION_up_ref(&session_);
103 #endif
104   }
105 }
106
107 void SSLSessionImpl::downRef() {
108   if (session_) {
109     SSL_SESSION_free(session_);
110   }
111 }
112
113 } // namespace detail
114 } // namespace ssl
115 } // namespace folly