/src/resiprocate/rutil/DigestStream.cxx
Line | Count | Source |
1 | | // For testing - also uncomment this in testDigestStream.cxx to test non-SSL MD5 and SHA1 |
2 | | //#undef USE_SSL |
3 | | |
4 | | #include "rutil/DigestStream.hxx" |
5 | | |
6 | | // Remove warning about 'this' use in initiator list - pointer is only stored |
7 | | #if defined(WIN32) && !defined(__GNUC__) |
8 | | #pragma warning( disable : 4355 ) // using this in base member initializer list |
9 | | #endif |
10 | | |
11 | | #ifdef USE_SSL |
12 | | #include <openssl/evp.h> |
13 | | #if OPENSSL_VERSION_NUMBER < 0x10100000L // openssl 1.1.0 api changes |
14 | | static EVP_MD_CTX* EVP_MD_CTX_new() |
15 | | { |
16 | | return new EVP_MD_CTX; |
17 | | } |
18 | | static void EVP_MD_CTX_free(EVP_MD_CTX* pCtx) |
19 | | { |
20 | | EVP_MD_CTX_cleanup(pCtx); |
21 | | delete pCtx; |
22 | | } |
23 | | #endif |
24 | | #else |
25 | | #include "rutil/vmd5.hxx" |
26 | | #include "rutil/Sha1.hxx" |
27 | | #endif |
28 | | |
29 | | using namespace resip; |
30 | | |
31 | | DigestBuffer::DigestBuffer(DigestType digestType) : |
32 | 0 | mDigestType(digestType), |
33 | 0 | mContext(nullptr), |
34 | 0 | mBytesTaken(0), |
35 | | #ifdef USE_SSL |
36 | | mFinalBin(EVP_MAX_MD_SIZE, Data::Preallocate) |
37 | | #else |
38 | 0 | mFinalBin(16, Data::Preallocate) |
39 | | #endif |
40 | 0 | { |
41 | 0 | int ret = 0; |
42 | 0 | switch (digestType) |
43 | 0 | { |
44 | 0 | case MD5: |
45 | | #ifdef USE_SSL |
46 | | mContext = EVP_MD_CTX_new(); |
47 | | EVP_MD_CTX_init((EVP_MD_CTX*)mContext); |
48 | | ret = EVP_DigestInit_ex((EVP_MD_CTX*)mContext, EVP_md5(), nullptr); |
49 | | #else |
50 | 0 | mContext = new MD5Context; |
51 | 0 | MD5Init((MD5Context*)mContext); |
52 | 0 | ret = 1; |
53 | 0 | #endif |
54 | 0 | break; |
55 | 0 | case SHA1: |
56 | | #ifdef USE_SSL |
57 | | mContext = EVP_MD_CTX_new(); |
58 | | EVP_MD_CTX_init((EVP_MD_CTX*)mContext); |
59 | | ret = EVP_DigestInit_ex((EVP_MD_CTX*)mContext, EVP_sha1(), nullptr); |
60 | | #else |
61 | 0 | mContext = new Sha1(); |
62 | 0 | ret = 1; |
63 | 0 | #endif |
64 | 0 | break; |
65 | | #ifdef USE_SSL |
66 | | case SHA256: |
67 | | mContext = EVP_MD_CTX_new(); |
68 | | EVP_MD_CTX_init((EVP_MD_CTX*)mContext); |
69 | | ret = EVP_DigestInit_ex((EVP_MD_CTX*)mContext, EVP_sha256(), nullptr); |
70 | | break; |
71 | | case SHA512: |
72 | | mContext = EVP_MD_CTX_new(); |
73 | | EVP_MD_CTX_init((EVP_MD_CTX*)mContext); |
74 | | ret = EVP_DigestInit_ex((EVP_MD_CTX*)mContext, EVP_sha512(), nullptr); |
75 | | break; |
76 | | case SHA512_256: |
77 | | mContext = EVP_MD_CTX_new(); |
78 | | EVP_MD_CTX_init((EVP_MD_CTX*)mContext); |
79 | | ret = EVP_DigestInit_ex((EVP_MD_CTX*)mContext, EVP_sha512_256(), nullptr); |
80 | | break; |
81 | | #endif |
82 | 0 | default: |
83 | 0 | resip_assert(false); |
84 | 0 | break; |
85 | 0 | } |
86 | 0 | if (!ret) |
87 | 0 | { |
88 | 0 | throw std::runtime_error("Failed to initialize digest context"); |
89 | 0 | } |
90 | 0 | setp(mBuf, mBuf + sizeof(mBuf)); |
91 | 0 | } |
92 | | |
93 | | DigestBuffer::~DigestBuffer() |
94 | 0 | { |
95 | | #ifdef USE_SSL |
96 | | EVP_MD_CTX_free((EVP_MD_CTX*)mContext); |
97 | | #else |
98 | 0 | if (mDigestType == MD5) |
99 | 0 | { |
100 | 0 | delete (MD5Context*)mContext; |
101 | 0 | } |
102 | 0 | else if (mDigestType == SHA1) |
103 | 0 | { |
104 | 0 | delete (resip::Sha1*)mContext; |
105 | 0 | } |
106 | 0 | #endif |
107 | 0 | } |
108 | | |
109 | | int |
110 | | DigestBuffer::sync() |
111 | 0 | { |
112 | 0 | if (!mContext) return -1; |
113 | | |
114 | 0 | size_t len = pptr() - pbase(); |
115 | 0 | if (len > 0) |
116 | 0 | { |
117 | | #ifdef USE_SSL |
118 | | EVP_DigestUpdate((EVP_MD_CTX*)mContext, reinterpret_cast <unsigned const char*>(pbase()), len); |
119 | | #else |
120 | 0 | if (mDigestType == MD5) |
121 | 0 | { |
122 | 0 | MD5Update((MD5Context*)mContext, reinterpret_cast <unsigned const char*>(pbase()), (unsigned int)len); |
123 | 0 | } |
124 | 0 | else if (mDigestType == SHA1) |
125 | 0 | { |
126 | 0 | ((Sha1*)mContext)->update(std::string(pbase(), len)); |
127 | 0 | } |
128 | 0 | #endif |
129 | | // reset the put buffer |
130 | 0 | setp(mBuf, mBuf + sizeof(mBuf)); |
131 | 0 | mBytesTaken += len; |
132 | 0 | } |
133 | 0 | return 0; |
134 | 0 | } |
135 | | |
136 | | int |
137 | | DigestBuffer::overflow(int c) |
138 | 0 | { |
139 | 0 | sync(); |
140 | 0 | if (c != -1) |
141 | 0 | { |
142 | 0 | mBuf[0] = c; |
143 | 0 | pbump(1); |
144 | 0 | return c; |
145 | 0 | } |
146 | 0 | return 0; |
147 | 0 | } |
148 | | |
149 | | Data |
150 | | DigestBuffer::getHex() |
151 | 0 | { |
152 | 0 | return getBin().hex(); |
153 | 0 | } |
154 | | |
155 | | const Data& |
156 | | DigestBuffer::getBin() |
157 | 0 | { |
158 | | // If not already calculated, then calcuate it |
159 | 0 | if (mFinalBin.size() == 0) |
160 | 0 | { |
161 | | #ifdef USE_SSL |
162 | | unsigned int len = EVP_MAX_MD_SIZE; |
163 | | EVP_DigestFinal_ex((EVP_MD_CTX*)mContext, (unsigned char*)mFinalBin.getBuf(len), &len); |
164 | | mFinalBin.truncate(len); |
165 | | #else |
166 | 0 | if (mDigestType == MD5) |
167 | 0 | { |
168 | 0 | MD5Final((unsigned char*)mFinalBin.getBuf(16), (MD5Context*)mContext); |
169 | 0 | } |
170 | 0 | else if (mDigestType == SHA1) |
171 | 0 | { |
172 | 0 | mFinalBin = ((Sha1*)mContext)->finalBin(); |
173 | 0 | } |
174 | 0 | #endif |
175 | 0 | } |
176 | 0 | return mFinalBin; |
177 | 0 | } |
178 | | |
179 | | DigestStream::DigestStream(DigestType digestType) |
180 | 0 | : DigestBuffer(digestType), std::ostream(this) |
181 | 0 | { |
182 | 0 | } Unexecuted instantiation: resip::DigestStream::DigestStream(resip::DigestType) Unexecuted instantiation: resip::DigestStream::DigestStream(resip::DigestType) |
183 | | |
184 | | DigestStream::~DigestStream() |
185 | 0 | { |
186 | 0 | } |
187 | | |
188 | | Data |
189 | | DigestStream::getHex() |
190 | 0 | { |
191 | 0 | flush(); |
192 | 0 | return DigestBuffer::getHex(); |
193 | 0 | } |
194 | | |
195 | | const Data& |
196 | | DigestStream::getBin() |
197 | 0 | { |
198 | 0 | flush(); |
199 | 0 | return DigestBuffer::getBin(); |
200 | 0 | } |
201 | | |
202 | | size_t |
203 | | DigestStream::bytesTaken() |
204 | 0 | { |
205 | 0 | return DigestBuffer::bytesTaken(); |
206 | 0 | } |
207 | | |
208 | | static Data md5Name("MD5"); |
209 | | static Data sha1Name("SHA1"); |
210 | | #ifdef USE_SSL |
211 | | static Data sha256Name("SHA-256"); |
212 | | static Data sha512Name("SHA-512"); |
213 | | static Data sha512_256Name("SHA-512-256"); |
214 | | #endif |
215 | | const Data& |
216 | | DigestStream::getDigestName(DigestType digestType) |
217 | 0 | { |
218 | | // Note: This name formatting aligns with what is needed in the SIP |
219 | | // Digest authentication header 'algorithm' parameter (where it makes sense). |
220 | 0 | switch (digestType) |
221 | 0 | { |
222 | 0 | case MD5: |
223 | 0 | return md5Name; |
224 | 0 | case SHA1: |
225 | 0 | return sha1Name; |
226 | | #ifdef USE_SSL |
227 | | case SHA256: |
228 | | return sha256Name; |
229 | | case SHA512: |
230 | | return sha512Name; |
231 | | case SHA512_256: |
232 | | return sha512_256Name; |
233 | | #endif |
234 | 0 | default: |
235 | | resip_assert(false); |
236 | 0 | return Data::Empty; |
237 | 0 | } |
238 | 0 | } |
239 | | |
240 | | |
241 | | /* ==================================================================== |
242 | | * The Vovida Software License, Version 1.0 |
243 | | * |
244 | | * Copyright (c) 2026 SIP Spectrum, Inc. https://www.sipspectrum.com |
245 | | * Copyright (c) 2000 Vovida Networks, Inc. All rights reserved. |
246 | | * |
247 | | * Redistribution and use in source and binary forms, with or without |
248 | | * modification, are permitted provided that the following conditions |
249 | | * are met: |
250 | | * |
251 | | * 1. Redistributions of source code must retain the above copyright |
252 | | * notice, this list of conditions and the following disclaimer. |
253 | | * |
254 | | * 2. Redistributions in binary form must reproduce the above copyright |
255 | | * notice, this list of conditions and the following disclaimer in |
256 | | * the documentation and/or other materials provided with the |
257 | | * distribution. |
258 | | * |
259 | | * 3. The names "VOCAL", "Vovida Open Communication Application Library", |
260 | | * and "Vovida Open Communication Application Library (VOCAL)" must |
261 | | * not be used to endorse or promote products derived from this |
262 | | * software without prior written permission. For written |
263 | | * permission, please contact vocal@vovida.org. |
264 | | * |
265 | | * 4. Products derived from this software may not be called "VOCAL", nor |
266 | | * may "VOCAL" appear in their name, without prior written |
267 | | * permission of Vovida Networks, Inc. |
268 | | * |
269 | | * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED |
270 | | * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
271 | | * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND |
272 | | * NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL VOVIDA |
273 | | * NETWORKS, INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT DAMAGES |
274 | | * IN EXCESS OF $1,000, NOR FOR ANY INDIRECT, INCIDENTAL, SPECIAL, |
275 | | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
276 | | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR |
277 | | * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY |
278 | | * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
279 | | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE |
280 | | * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH |
281 | | * DAMAGE. |
282 | | * |
283 | | * ==================================================================== |
284 | | * |
285 | | * This software consists of voluntary contributions made by Vovida |
286 | | * Networks, Inc. and many individuals on behalf of Vovida Networks, |
287 | | * Inc. For more information on Vovida Networks, Inc., please see |
288 | | * <http://www.vovida.org/>. |
289 | | * |
290 | | */ |