Coverage Report

Created: 2026-02-13 06:31

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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
 */