AudioSrtpSession.cpp 9.4 KB
Newer Older
1
/*
2
 *  Copyright (C) 2004, 2005, 2006, 2009, 2008, 2009, 2010 Savoir-Faire Linux Inc.
3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
 *  Author: Alexandre Savard <alexandre.savard@savoirfairelinux.com>
 *  Author: Pierre-Luc Bacon <pierre-luc.bacon@savoirfairelinux.com>
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 3 of the License, or
 *  (at your option) any later version.
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 19 20 21 22 23 24 25 26 27 28
 *
 *  Additional permission under GNU GPL version 3 section 7:
 *
 *  If you modify this program, or any covered work, by linking or
 *  combining it with the OpenSSL project's OpenSSL library (or a
 *  modified version of that library), containing parts covered by the
 *  terms of the OpenSSL or SSLeay licenses, Savoir-Faire Linux Inc.
 *  grants you additional permission to convey the resulting work.
 *  Corresponding Source for a non-source form of such a combination
 *  shall include the source code for the parts of OpenSSL used as well
 *  as that of the covered work.
29 30 31 32 33 34
 */
#include "AudioSrtpSession.h"
#include "user_cfg.h"

#include "sip/sipcall.h"

35 36
#include <openssl/sha.h>
#include <openssl/hmac.h>
37
#include <openssl/evp.h>
38 39
#include <openssl/bio.h>
#include <openssl/buffer.h>
40
#include <openssl/rand.h>
41 42


43 44 45 46
#include <cstdio>
#include <cstring>
#include <cerrno>

47

48 49 50 51 52
namespace sfl
{

AudioSrtpSession::AudioSrtpSession (ManagerImpl * manager, SIPCall * sipcall) :
        ost::SymmetricRTPSession (ost::InetHostAddress (sipcall->getLocalIp().c_str()), sipcall->getLocalAudioPort()),
Alexandre Savard's avatar
Alexandre Savard committed
53 54 55 56 57 58 59 60
        AudioRtpSession<AudioSrtpSession> (manager, sipcall),
        _localCryptoSuite(0),
        _remoteCryptoSuite(0),
        _localMasterKeyLength(0),
        _localMasterSaltLength(0),
        _remoteMasterKeyLength(0),
        _remoteMasterSaltLength(0)

61
{
62 63

    // Initialize local Crypto context
64 65 66
    initializeLocalMasterKey();
    initializeLocalMasterSalt();
    initializeLocalCryptoContext();
67

68
    // Set local crypto context in ccrtp
69
    _localCryptoCtx->deriveSrtpKeys(0);
70

71
    setOutQueueCryptoContext(_localCryptoCtx);
72 73
}

74
 
75
std::vector<std::string> AudioSrtpSession::getLocalCryptoInfo() {
76

77 78
    _debug("Get Cryptographic info from this rtp session");

79 80
    std::vector<std::string> crypto_vector;

81 82
    // @TODO we should return a vector containing supported 
    // cryptographic context tagged 1, 2, 3...
83
    std::string tag = "1";
84

85
    std::string crypto_suite = sfl::CryptoSuites[_localCryptoSuite].name;
86

87
    // srtp keys formated as the following  as the following
88
    // inline:keyParameters|keylifetime|MasterKeyIdentifier
89
    // inline:NzB4d1BINUAvLEw6UzF3WSJ+PSdFcGdUJShpX1Zj|2^20|1:32
90 91
    std::string srtp_keys = "inline:";
    srtp_keys += getBase64ConcatenatedKeys();
92
    // srtp_keys.append("|2^20|1:32");
93

94
    // generate crypto attribute
95 96 97 98 99
    std::string crypto_attr = tag.append(" ");
    crypto_attr += crypto_suite.append(" ");
    crypto_attr += srtp_keys;

    _debug("%s", crypto_attr.c_str());
100

101
    crypto_vector.push_back(crypto_attr);
102

103
    return crypto_vector;
104
}
105

106

107
void AudioSrtpSession::setRemoteCryptoInfo(sfl::SdesNegotiator& nego) {
108

109
    _debug("Set remote Cryptographic info for Srtp");
110

111
    // decode keys
112
    unBase64ConcatenatedKeys(nego.getKeyInfo());
113 114

    // init crypto content int Srtp session
115
    initializeRemoteCryptoContext();
116
    setInQueueCryptoContext(_remoteCryptoCtx);
117 118 119
}


120
void AudioSrtpSession::initializeLocalMasterKey(void)
121
{
122

123
    // @TODO key may have different length depending on cipher suite
124
    _localMasterKeyLength = sfl::CryptoSuites[_localCryptoSuite].masterKeyLength / 8;
125

126
    // Allocate memory for key
127 128
    unsigned char *random_key = new unsigned char[_localMasterKeyLength];

129
    // Generate ryptographically strong pseudo-random bytes
130 131 132 133
    int err;
    if((err = RAND_bytes(random_key, _localMasterKeyLength)) != 1)
        _debug("Error occured while generating cryptographically strong pseudo-random key");

134
    memcpy(_localMasterKey, random_key, _localMasterKeyLength);
135

136
    /*
137
    printf("Local Master: ");
138
    for(int i = 0; i < _localMasterKeyLength; i++){
139
        printf("%d", _localMasterKey[i]);
140
    }
141
    printf("\n");
142
    */
143 144 145 146
    return;
}


147
void AudioSrtpSession::initializeLocalMasterSalt(void)
148
{
149

150
    // @TODO key may have different length depending on cipher suite 
151
  _localMasterSaltLength = sfl::CryptoSuites[_localCryptoSuite].masterSaltLength / 8;
152

153
    // Allocate memory for key
154 155
    unsigned char *random_key = new unsigned char[_localMasterSaltLength];

156
    // Generate ryptographically strong pseudo-random bytes
157 158 159 160
    int err;
    if((err = RAND_bytes(random_key, _localMasterSaltLength)) != 1)
        _debug("Error occured while generating cryptographically strong pseudo-random key");

161
    memcpy(_localMasterSalt, random_key, _localMasterSaltLength);
162

163 164 165 166
    return;

}

167 168 169 170

std::string AudioSrtpSession::getBase64ConcatenatedKeys()
{

171
    // compute concatenated master and salt length
172
    int concatLength = _localMasterKeyLength + _localMasterSaltLength;
173

174
    uint8 concatKeys[concatLength];
175 176

    // concatenate keys
177 178
    memcpy((void*)concatKeys, (void*)_localMasterKey, _localMasterKeyLength);
    memcpy((void*)(concatKeys + _localMasterKeyLength), (void*)_localMasterSalt, _localMasterSaltLength);
179

180
    // encode concatenated keys in base64
181
    char *output = encodeBase64((unsigned char*)concatKeys, concatLength);
182

183
    // init string containing encoded data
184 185 186 187 188 189 190 191
    std::string keys(output);

    free(output);

    return keys;
}


192
void AudioSrtpSession::unBase64ConcatenatedKeys(std::string base64keys)
193 194
{

195 196
    _remoteMasterKeyLength = sfl::CryptoSuites[1].masterKeyLength / 8;
    _remoteMasterSaltLength = sfl::CryptoSuites[1].masterSaltLength / 8;
197

198
    // length of decoded data data
199 200
    int length;

201
    // pointer to binary data
202 203
    char *dataptr = (char*)base64keys.data();

204
    // decode concatenated binary keys
205 206
    char *output = decodeBase64((unsigned char*)dataptr, strlen(dataptr), &length);

207
    // copy master and slt respectively
208 209 210
    memcpy((void*)_remoteMasterKey, (void*)output, _remoteMasterKeyLength);
    memcpy((void*)_remoteMasterSalt, (void*)(output + _remoteMasterKeyLength), _remoteMasterSaltLength);

211 212 213 214 215
    free(output);
}


void AudioSrtpSession::initializeRemoteCryptoContext(void)
216
{
217
    CryptoSuiteDefinition crypto = sfl::CryptoSuites[_localCryptoSuite];
218

219
    _remoteCryptoCtx = new ost::CryptoContext(0x0,
220 221 222 223 224 225 226 227 228 229 230 231
					     0,                               // roc,
					     0L,                              // keydr,
					     SrtpEncryptionAESCM,             // encryption algo
					     SrtpAuthenticationSha1Hmac,      // authtication algo
					     _remoteMasterKey,            
					     _remoteMasterKeyLength,      
					     _remoteMasterSalt,           
					     _remoteMasterSaltLength,       
					     crypto.encryptionKeyLength / 8, 
					     crypto.srtpAuthKeyLength / 8,
					     112 / 8,                         // session salt len
					     crypto.srtpAuthTagLength / 8);
232 233 234
    
}

235
void AudioSrtpSession::initializeLocalCryptoContext(void)
236
{
237
    CryptoSuiteDefinition crypto = sfl::CryptoSuites[_localCryptoSuite];
238

239
    _localCryptoCtx = new ost::CryptoContext(OutgoingDataQueue::getLocalSSRC(),
240 241 242 243 244 245 246 247 248 249 250 251
					      0,                               // roc,
					      0L,                              // keydr,
					      SrtpEncryptionAESCM,             // encryption algo
					      SrtpAuthenticationSha1Hmac,      // authtication algo
					      _localMasterKey,             
					      _localMasterKeyLength,       
					      _localMasterSalt,            
					      _localMasterSaltLength,      
					      crypto.encryptionKeyLength / 8,
					      crypto.srtpAuthKeyLength / 8,
					      112 / 8,                         // session salt len
					      crypto.srtpAuthTagLength / 8);
252 253 254

}

Julien Bonjean's avatar
Julien Bonjean committed
255
#pragma GCC diagnostic ignored "-Wunused-value"
256 257 258
char* AudioSrtpSession::encodeBase64(unsigned char *input, int length)
{
    BIO *b64, *bmem;
259
    BUF_MEM *bptr ;
260

261 262
    char *buffer = (char *)malloc(2*length);
    memset(buffer, 0, 2*length);
263

264
    // init decoder
265
    b64 = BIO_new(BIO_f_base64());
266
    BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL);
267 268

    // init internal buffer
269
    bmem = BIO_new(BIO_s_mem());
270

271 272 273 274 275 276 277 278 279
    // create decoder chain
    b64 = BIO_push(b64, bmem);

    BIO_write(b64, input, length);
    BIO_flush(b64);

    // get pointer to data
    BIO_get_mem_ptr(b64, &bptr);

280
    // copy result in output buffer (-1 since we do not want the EOF character)
281
    strncpy(buffer, (char*)(bptr->data), bptr->length);
282 283 284

    BIO_free_all(bmem);

285
    return buffer;    
286
}
Julien Bonjean's avatar
Julien Bonjean committed
287
#pragma GCC diagnostic error "-Wunused-value"
288

289
char* AudioSrtpSession::decodeBase64(unsigned char *input, int length, int *length_out)
290 291 292 293 294
{
    BIO *b64, *bmem;

    char *buffer = (char *)malloc(length);
    memset(buffer, 0, length);
295 296

    // init decoder and read-only BIO buffer
297
    b64 = BIO_new(BIO_f_base64());
298
    BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL);
299 300

    // init internal buffer
301
    bmem = BIO_new_mem_buf(input, length);
302 303

    // create encoder chain
304
    bmem = BIO_push(b64, bmem);
305

306
    *length_out = BIO_read(bmem, buffer, length);
307 308 309 310

    BIO_free_all(bmem);

    return buffer;
311

312
}
313

314
}