1238104Sdes/* 2238104Sdes * tsig.c 3238104Sdes * 4238104Sdes * contains the functions needed for TSIG [RFC2845] 5238104Sdes * 6238104Sdes * (c) 2005-2006 NLnet Labs 7238104Sdes * See the file LICENSE for the license 8238104Sdes */ 9238104Sdes 10238104Sdes#include <ldns/config.h> 11238104Sdes 12238104Sdes#include <ldns/ldns.h> 13238104Sdes 14238104Sdes#include <strings.h> 15238104Sdes 16238104Sdes#ifdef HAVE_SSL 17238104Sdes#include <openssl/hmac.h> 18238104Sdes#include <openssl/md5.h> 19238104Sdes#endif /* HAVE_SSL */ 20238104Sdes 21238104Sdeschar * 22238104Sdesldns_tsig_algorithm(ldns_tsig_credentials *tc) 23238104Sdes{ 24238104Sdes return tc->algorithm; 25238104Sdes} 26238104Sdes 27238104Sdeschar * 28238104Sdesldns_tsig_keyname(ldns_tsig_credentials *tc) 29238104Sdes{ 30238104Sdes return tc->keyname; 31238104Sdes} 32238104Sdes 33238104Sdeschar * 34238104Sdesldns_tsig_keydata(ldns_tsig_credentials *tc) 35238104Sdes{ 36238104Sdes return tc->keydata; 37238104Sdes} 38238104Sdes 39238104Sdeschar * 40238104Sdesldns_tsig_keyname_clone(ldns_tsig_credentials *tc) 41238104Sdes{ 42238104Sdes return strdup(tc->keyname); 43238104Sdes} 44238104Sdes 45238104Sdeschar * 46238104Sdesldns_tsig_keydata_clone(ldns_tsig_credentials *tc) 47238104Sdes{ 48238104Sdes return strdup(tc->keydata); 49238104Sdes} 50238104Sdes 51238104Sdes/* 52238104Sdes * Makes an exact copy of the wire, but with the tsig rr removed 53238104Sdes */ 54246827Sdesstatic uint8_t * 55238104Sdesldns_tsig_prepare_pkt_wire(uint8_t *wire, size_t wire_len, size_t *result_len) 56238104Sdes{ 57238104Sdes uint8_t *wire2 = NULL; 58238104Sdes uint16_t qd_count; 59238104Sdes uint16_t an_count; 60238104Sdes uint16_t ns_count; 61238104Sdes uint16_t ar_count; 62238104Sdes ldns_rr *rr; 63238104Sdes 64238104Sdes size_t pos; 65238104Sdes uint16_t i; 66238104Sdes 67238104Sdes ldns_status status; 68238104Sdes 69238104Sdes if(wire_len < LDNS_HEADER_SIZE) { 70238104Sdes return NULL; 71238104Sdes } 72238104Sdes /* fake parse the wire */ 73238104Sdes qd_count = LDNS_QDCOUNT(wire); 74238104Sdes an_count = LDNS_ANCOUNT(wire); 75238104Sdes ns_count = LDNS_NSCOUNT(wire); 76238104Sdes ar_count = LDNS_ARCOUNT(wire); 77238104Sdes 78238104Sdes if (ar_count > 0) { 79238104Sdes ar_count--; 80238104Sdes } else { 81238104Sdes return NULL; 82238104Sdes } 83238104Sdes 84238104Sdes pos = LDNS_HEADER_SIZE; 85238104Sdes 86238104Sdes for (i = 0; i < qd_count; i++) { 87238104Sdes status = ldns_wire2rr(&rr, wire, wire_len, &pos, LDNS_SECTION_QUESTION); 88238104Sdes if (status != LDNS_STATUS_OK) { 89238104Sdes return NULL; 90238104Sdes } 91238104Sdes ldns_rr_free(rr); 92238104Sdes } 93238104Sdes 94238104Sdes for (i = 0; i < an_count; i++) { 95238104Sdes status = ldns_wire2rr(&rr, wire, wire_len, &pos, LDNS_SECTION_ANSWER); 96238104Sdes if (status != LDNS_STATUS_OK) { 97238104Sdes return NULL; 98238104Sdes } 99238104Sdes ldns_rr_free(rr); 100238104Sdes } 101238104Sdes 102238104Sdes for (i = 0; i < ns_count; i++) { 103238104Sdes status = ldns_wire2rr(&rr, wire, wire_len, &pos, LDNS_SECTION_AUTHORITY); 104238104Sdes if (status != LDNS_STATUS_OK) { 105238104Sdes return NULL; 106238104Sdes } 107238104Sdes ldns_rr_free(rr); 108238104Sdes } 109238104Sdes 110238104Sdes for (i = 0; i < ar_count; i++) { 111238104Sdes status = ldns_wire2rr(&rr, wire, wire_len, &pos, 112238104Sdes LDNS_SECTION_ADDITIONAL); 113238104Sdes if (status != LDNS_STATUS_OK) { 114238104Sdes return NULL; 115238104Sdes } 116238104Sdes ldns_rr_free(rr); 117238104Sdes } 118238104Sdes 119238104Sdes *result_len = pos; 120238104Sdes wire2 = LDNS_XMALLOC(uint8_t, *result_len); 121238104Sdes if(!wire2) { 122238104Sdes return NULL; 123238104Sdes } 124238104Sdes memcpy(wire2, wire, *result_len); 125238104Sdes 126238104Sdes ldns_write_uint16(wire2 + LDNS_ARCOUNT_OFF, ar_count); 127238104Sdes 128238104Sdes return wire2; 129238104Sdes} 130238104Sdes 131238104Sdes#ifdef HAVE_SSL 132238104Sdesstatic const EVP_MD * 133238104Sdesldns_digest_function(char *name) 134238104Sdes{ 135238104Sdes /* these are the mandatory algorithms from RFC4635 */ 136238104Sdes /* The optional algorithms are not yet implemented */ 137269257Sdes if (strcasecmp(name, "hmac-sha256.") == 0) { 138238104Sdes#ifdef HAVE_EVP_SHA256 139238104Sdes return EVP_sha256(); 140238104Sdes#else 141238104Sdes return NULL; 142238104Sdes#endif 143269257Sdes } else if (strcasecmp(name, "hmac-sha1.") == 0) { 144238104Sdes return EVP_sha1(); 145269257Sdes } else if (strcasecmp(name, "hmac-md5.sig-alg.reg.int.") == 0) { 146238104Sdes return EVP_md5(); 147238104Sdes } else { 148238104Sdes return NULL; 149238104Sdes } 150238104Sdes} 151238104Sdes#endif 152238104Sdes 153238104Sdes#ifdef HAVE_SSL 154238104Sdesstatic ldns_status 155238104Sdesldns_tsig_mac_new(ldns_rdf **tsig_mac, uint8_t *pkt_wire, size_t pkt_wire_size, 156238104Sdes const char *key_data, ldns_rdf *key_name_rdf, ldns_rdf *fudge_rdf, 157238104Sdes ldns_rdf *algorithm_rdf, ldns_rdf *time_signed_rdf, ldns_rdf *error_rdf, 158238104Sdes ldns_rdf *other_data_rdf, ldns_rdf *orig_mac_rdf, int tsig_timers_only) 159238104Sdes{ 160238104Sdes ldns_status status; 161238104Sdes char *wireformat; 162238104Sdes int wiresize; 163238104Sdes unsigned char *mac_bytes = NULL; 164238104Sdes unsigned char *key_bytes = NULL; 165238104Sdes int key_size; 166238104Sdes const EVP_MD *digester; 167238104Sdes char *algorithm_name = NULL; 168238104Sdes unsigned int md_len = EVP_MAX_MD_SIZE; 169238104Sdes ldns_rdf *result = NULL; 170238104Sdes ldns_buffer *data_buffer = NULL; 171238104Sdes ldns_rdf *canonical_key_name_rdf = NULL; 172238104Sdes ldns_rdf *canonical_algorithm_rdf = NULL; 173238104Sdes 174238104Sdes if (key_name_rdf == NULL || algorithm_rdf == NULL) { 175238104Sdes return LDNS_STATUS_NULL; 176238104Sdes } 177238104Sdes canonical_key_name_rdf = ldns_rdf_clone(key_name_rdf); 178246854Sdes if (canonical_key_name_rdf == NULL) { 179246854Sdes return LDNS_STATUS_MEM_ERR; 180246854Sdes } 181238104Sdes canonical_algorithm_rdf = ldns_rdf_clone(algorithm_rdf); 182246854Sdes if (canonical_algorithm_rdf == NULL) { 183246854Sdes ldns_rdf_deep_free(canonical_key_name_rdf); 184238104Sdes return LDNS_STATUS_MEM_ERR; 185238104Sdes } 186238104Sdes /* 187238104Sdes * prepare the digestable information 188238104Sdes */ 189238104Sdes data_buffer = ldns_buffer_new(LDNS_MAX_PACKETLEN); 190238104Sdes if (!data_buffer) { 191238104Sdes status = LDNS_STATUS_MEM_ERR; 192238104Sdes goto clean; 193238104Sdes } 194238104Sdes /* if orig_mac is not NULL, add it too */ 195238104Sdes if (orig_mac_rdf) { 196238104Sdes (void) ldns_rdf2buffer_wire(data_buffer, orig_mac_rdf); 197238104Sdes } 198238104Sdes ldns_buffer_write(data_buffer, pkt_wire, pkt_wire_size); 199238104Sdes if (!tsig_timers_only) { 200238104Sdes ldns_dname2canonical(canonical_key_name_rdf); 201238104Sdes (void)ldns_rdf2buffer_wire(data_buffer, 202238104Sdes canonical_key_name_rdf); 203238104Sdes ldns_buffer_write_u16(data_buffer, LDNS_RR_CLASS_ANY); 204238104Sdes ldns_buffer_write_u32(data_buffer, 0); 205238104Sdes ldns_dname2canonical(canonical_algorithm_rdf); 206238104Sdes (void)ldns_rdf2buffer_wire(data_buffer, 207238104Sdes canonical_algorithm_rdf); 208238104Sdes } 209238104Sdes (void)ldns_rdf2buffer_wire(data_buffer, time_signed_rdf); 210238104Sdes (void)ldns_rdf2buffer_wire(data_buffer, fudge_rdf); 211238104Sdes if (!tsig_timers_only) { 212238104Sdes (void)ldns_rdf2buffer_wire(data_buffer, error_rdf); 213238104Sdes (void)ldns_rdf2buffer_wire(data_buffer, other_data_rdf); 214238104Sdes } 215238104Sdes 216238104Sdes wireformat = (char *) data_buffer->_data; 217238104Sdes wiresize = (int) ldns_buffer_position(data_buffer); 218238104Sdes 219238104Sdes algorithm_name = ldns_rdf2str(algorithm_rdf); 220238104Sdes if(!algorithm_name) { 221238104Sdes status = LDNS_STATUS_MEM_ERR; 222238104Sdes goto clean; 223238104Sdes } 224238104Sdes 225238104Sdes /* prepare the key */ 226238104Sdes key_bytes = LDNS_XMALLOC(unsigned char, 227238104Sdes ldns_b64_pton_calculate_size(strlen(key_data))); 228238104Sdes if(!key_bytes) { 229238104Sdes status = LDNS_STATUS_MEM_ERR; 230238104Sdes goto clean; 231238104Sdes } 232238104Sdes key_size = ldns_b64_pton(key_data, key_bytes, 233238104Sdes ldns_b64_pton_calculate_size(strlen(key_data))); 234238104Sdes if (key_size < 0) { 235238104Sdes status = LDNS_STATUS_INVALID_B64; 236238104Sdes goto clean; 237238104Sdes } 238238104Sdes /* hmac it */ 239238104Sdes /* 2 spare bytes for the length */ 240238104Sdes mac_bytes = LDNS_XMALLOC(unsigned char, md_len+2); 241238104Sdes if(!mac_bytes) { 242238104Sdes status = LDNS_STATUS_MEM_ERR; 243238104Sdes goto clean; 244238104Sdes } 245238104Sdes memset(mac_bytes, 0, md_len+2); 246238104Sdes 247238104Sdes digester = ldns_digest_function(algorithm_name); 248238104Sdes 249238104Sdes if (digester) { 250238104Sdes (void) HMAC(digester, key_bytes, key_size, (void *)wireformat, 251238104Sdes (size_t) wiresize, mac_bytes + 2, &md_len); 252238104Sdes 253238104Sdes ldns_write_uint16(mac_bytes, md_len); 254238104Sdes result = ldns_rdf_new_frm_data(LDNS_RDF_TYPE_INT16_DATA, md_len + 2, 255238104Sdes mac_bytes); 256238104Sdes } else { 257238104Sdes status = LDNS_STATUS_CRYPTO_UNKNOWN_ALGO; 258238104Sdes goto clean; 259238104Sdes } 260238104Sdes *tsig_mac = result; 261238104Sdes status = LDNS_STATUS_OK; 262238104Sdes clean: 263238104Sdes LDNS_FREE(mac_bytes); 264238104Sdes LDNS_FREE(key_bytes); 265238104Sdes LDNS_FREE(algorithm_name); 266238104Sdes ldns_buffer_free(data_buffer); 267246854Sdes ldns_rdf_deep_free(canonical_algorithm_rdf); 268246854Sdes ldns_rdf_deep_free(canonical_key_name_rdf); 269238104Sdes return status; 270238104Sdes} 271238104Sdes#endif /* HAVE_SSL */ 272238104Sdes 273238104Sdes 274238104Sdes#ifdef HAVE_SSL 275238104Sdesbool 276238104Sdesldns_pkt_tsig_verify(ldns_pkt *pkt, uint8_t *wire, size_t wirelen, const char *key_name, 277238104Sdes const char *key_data, ldns_rdf *orig_mac_rdf) 278238104Sdes{ 279238104Sdes return ldns_pkt_tsig_verify_next(pkt, wire, wirelen, key_name, key_data, orig_mac_rdf, 0); 280238104Sdes} 281238104Sdes 282238104Sdesbool 283238104Sdesldns_pkt_tsig_verify_next(ldns_pkt *pkt, uint8_t *wire, size_t wirelen, const char* key_name, 284238104Sdes const char *key_data, ldns_rdf *orig_mac_rdf, int tsig_timers_only) 285238104Sdes{ 286238104Sdes ldns_rdf *fudge_rdf; 287238104Sdes ldns_rdf *algorithm_rdf; 288238104Sdes ldns_rdf *time_signed_rdf; 289238104Sdes ldns_rdf *orig_id_rdf; 290238104Sdes ldns_rdf *error_rdf; 291238104Sdes ldns_rdf *other_data_rdf; 292238104Sdes ldns_rdf *pkt_mac_rdf; 293238104Sdes ldns_rdf *my_mac_rdf; 294238104Sdes ldns_rdf *key_name_rdf = ldns_rdf_new_frm_str(LDNS_RDF_TYPE_DNAME, key_name); 295238104Sdes uint16_t pkt_id, orig_pkt_id; 296238104Sdes ldns_status status; 297238104Sdes 298238104Sdes uint8_t *prepared_wire = NULL; 299238104Sdes size_t prepared_wire_size = 0; 300238104Sdes 301238104Sdes ldns_rr *orig_tsig = ldns_pkt_tsig(pkt); 302238104Sdes 303238104Sdes if (!orig_tsig || ldns_rr_rd_count(orig_tsig) <= 6) { 304238104Sdes ldns_rdf_deep_free(key_name_rdf); 305238104Sdes return false; 306238104Sdes } 307238104Sdes algorithm_rdf = ldns_rr_rdf(orig_tsig, 0); 308238104Sdes time_signed_rdf = ldns_rr_rdf(orig_tsig, 1); 309238104Sdes fudge_rdf = ldns_rr_rdf(orig_tsig, 2); 310238104Sdes pkt_mac_rdf = ldns_rr_rdf(orig_tsig, 3); 311238104Sdes orig_id_rdf = ldns_rr_rdf(orig_tsig, 4); 312238104Sdes error_rdf = ldns_rr_rdf(orig_tsig, 5); 313238104Sdes other_data_rdf = ldns_rr_rdf(orig_tsig, 6); 314238104Sdes 315238104Sdes /* remove temporarily */ 316238104Sdes ldns_pkt_set_tsig(pkt, NULL); 317238104Sdes /* temporarily change the id to the original id */ 318238104Sdes pkt_id = ldns_pkt_id(pkt); 319238104Sdes orig_pkt_id = ldns_rdf2native_int16(orig_id_rdf); 320238104Sdes ldns_pkt_set_id(pkt, orig_pkt_id); 321238104Sdes 322238104Sdes prepared_wire = ldns_tsig_prepare_pkt_wire(wire, wirelen, &prepared_wire_size); 323238104Sdes 324238104Sdes status = ldns_tsig_mac_new(&my_mac_rdf, prepared_wire, prepared_wire_size, 325238104Sdes key_data, key_name_rdf, fudge_rdf, algorithm_rdf, 326238104Sdes time_signed_rdf, error_rdf, other_data_rdf, orig_mac_rdf, tsig_timers_only); 327238104Sdes 328238104Sdes LDNS_FREE(prepared_wire); 329238104Sdes 330238104Sdes if (status != LDNS_STATUS_OK) { 331238104Sdes ldns_rdf_deep_free(key_name_rdf); 332238104Sdes return false; 333238104Sdes } 334238104Sdes /* Put back the values */ 335238104Sdes ldns_pkt_set_tsig(pkt, orig_tsig); 336238104Sdes ldns_pkt_set_id(pkt, pkt_id); 337238104Sdes 338238104Sdes ldns_rdf_deep_free(key_name_rdf); 339238104Sdes 340238104Sdes if (ldns_rdf_compare(pkt_mac_rdf, my_mac_rdf) == 0) { 341238104Sdes ldns_rdf_deep_free(my_mac_rdf); 342238104Sdes return true; 343238104Sdes } else { 344238104Sdes ldns_rdf_deep_free(my_mac_rdf); 345238104Sdes return false; 346238104Sdes } 347238104Sdes} 348238104Sdes#endif /* HAVE_SSL */ 349238104Sdes 350238104Sdes#ifdef HAVE_SSL 351238104Sdesldns_status 352238104Sdesldns_pkt_tsig_sign(ldns_pkt *pkt, const char *key_name, const char *key_data, 353238104Sdes uint16_t fudge, const char *algorithm_name, ldns_rdf *query_mac) 354238104Sdes{ 355238104Sdes return ldns_pkt_tsig_sign_next(pkt, key_name, key_data, fudge, algorithm_name, query_mac, 0); 356238104Sdes} 357238104Sdes 358238104Sdesldns_status 359238104Sdesldns_pkt_tsig_sign_next(ldns_pkt *pkt, const char *key_name, const char *key_data, 360238104Sdes uint16_t fudge, const char *algorithm_name, ldns_rdf *query_mac, int tsig_timers_only) 361238104Sdes{ 362238104Sdes ldns_rr *tsig_rr; 363238104Sdes ldns_rdf *key_name_rdf = ldns_rdf_new_frm_str(LDNS_RDF_TYPE_DNAME, key_name); 364238104Sdes ldns_rdf *fudge_rdf = NULL; 365238104Sdes ldns_rdf *orig_id_rdf = NULL; 366238104Sdes ldns_rdf *algorithm_rdf; 367238104Sdes ldns_rdf *error_rdf = NULL; 368238104Sdes ldns_rdf *mac_rdf = NULL; 369238104Sdes ldns_rdf *other_data_rdf = NULL; 370238104Sdes 371238104Sdes ldns_status status = LDNS_STATUS_OK; 372238104Sdes 373238104Sdes uint8_t *pkt_wire = NULL; 374238104Sdes size_t pkt_wire_len; 375238104Sdes 376238104Sdes struct timeval tv_time_signed; 377238104Sdes uint8_t *time_signed = NULL; 378238104Sdes ldns_rdf *time_signed_rdf = NULL; 379238104Sdes 380238104Sdes algorithm_rdf = ldns_rdf_new_frm_str(LDNS_RDF_TYPE_DNAME, algorithm_name); 381238104Sdes if(!key_name_rdf || !algorithm_rdf) { 382238104Sdes status = LDNS_STATUS_MEM_ERR; 383238104Sdes goto clean; 384238104Sdes } 385238104Sdes 386238104Sdes /* eww don't have create tsigtime rdf yet :( */ 387238104Sdes /* bleh :p */ 388238104Sdes if (gettimeofday(&tv_time_signed, NULL) == 0) { 389238104Sdes time_signed = LDNS_XMALLOC(uint8_t, 6); 390238104Sdes if(!time_signed) { 391238104Sdes status = LDNS_STATUS_MEM_ERR; 392238104Sdes goto clean; 393238104Sdes } 394238104Sdes ldns_write_uint64_as_uint48(time_signed, 395238104Sdes (uint64_t)tv_time_signed.tv_sec); 396238104Sdes } else { 397238104Sdes status = LDNS_STATUS_INTERNAL_ERR; 398238104Sdes goto clean; 399238104Sdes } 400238104Sdes 401238104Sdes time_signed_rdf = ldns_rdf_new(LDNS_RDF_TYPE_TSIGTIME, 6, time_signed); 402238104Sdes if(!time_signed_rdf) { 403238104Sdes LDNS_FREE(time_signed); 404238104Sdes status = LDNS_STATUS_MEM_ERR; 405238104Sdes goto clean; 406238104Sdes } 407238104Sdes 408238104Sdes fudge_rdf = ldns_native2rdf_int16(LDNS_RDF_TYPE_INT16, fudge); 409238104Sdes 410238104Sdes orig_id_rdf = ldns_native2rdf_int16(LDNS_RDF_TYPE_INT16, ldns_pkt_id(pkt)); 411238104Sdes 412238104Sdes error_rdf = ldns_native2rdf_int16(LDNS_RDF_TYPE_INT16, 0); 413238104Sdes 414238104Sdes other_data_rdf = ldns_native2rdf_int16_data(0, NULL); 415238104Sdes 416238104Sdes if(!fudge_rdf || !orig_id_rdf || !error_rdf || !other_data_rdf) { 417238104Sdes status = LDNS_STATUS_MEM_ERR; 418238104Sdes goto clean; 419238104Sdes } 420238104Sdes 421238104Sdes if (ldns_pkt2wire(&pkt_wire, pkt, &pkt_wire_len) != LDNS_STATUS_OK) { 422238104Sdes status = LDNS_STATUS_ERR; 423238104Sdes goto clean; 424238104Sdes } 425238104Sdes 426238104Sdes status = ldns_tsig_mac_new(&mac_rdf, pkt_wire, pkt_wire_len, 427238104Sdes key_data, key_name_rdf, fudge_rdf, algorithm_rdf, 428238104Sdes time_signed_rdf, error_rdf, other_data_rdf, query_mac, tsig_timers_only); 429238104Sdes 430238104Sdes if (!mac_rdf) { 431238104Sdes goto clean; 432238104Sdes } 433238104Sdes 434238104Sdes LDNS_FREE(pkt_wire); 435238104Sdes 436238104Sdes /* Create the TSIG RR */ 437238104Sdes tsig_rr = ldns_rr_new(); 438238104Sdes if(!tsig_rr) { 439238104Sdes status = LDNS_STATUS_MEM_ERR; 440238104Sdes goto clean; 441238104Sdes } 442238104Sdes ldns_rr_set_owner(tsig_rr, key_name_rdf); 443238104Sdes ldns_rr_set_class(tsig_rr, LDNS_RR_CLASS_ANY); 444238104Sdes ldns_rr_set_type(tsig_rr, LDNS_RR_TYPE_TSIG); 445238104Sdes ldns_rr_set_ttl(tsig_rr, 0); 446238104Sdes 447238104Sdes ldns_rr_push_rdf(tsig_rr, algorithm_rdf); 448238104Sdes ldns_rr_push_rdf(tsig_rr, time_signed_rdf); 449238104Sdes ldns_rr_push_rdf(tsig_rr, fudge_rdf); 450238104Sdes ldns_rr_push_rdf(tsig_rr, mac_rdf); 451238104Sdes ldns_rr_push_rdf(tsig_rr, orig_id_rdf); 452238104Sdes ldns_rr_push_rdf(tsig_rr, error_rdf); 453238104Sdes ldns_rr_push_rdf(tsig_rr, other_data_rdf); 454238104Sdes 455238104Sdes ldns_pkt_set_tsig(pkt, tsig_rr); 456238104Sdes 457238104Sdes return status; 458238104Sdes 459238104Sdes clean: 460238104Sdes LDNS_FREE(pkt_wire); 461238104Sdes ldns_rdf_free(key_name_rdf); 462238104Sdes ldns_rdf_free(algorithm_rdf); 463238104Sdes ldns_rdf_free(time_signed_rdf); 464238104Sdes ldns_rdf_free(fudge_rdf); 465238104Sdes ldns_rdf_free(orig_id_rdf); 466238104Sdes ldns_rdf_free(error_rdf); 467238104Sdes ldns_rdf_free(other_data_rdf); 468238104Sdes return status; 469238104Sdes} 470238104Sdes#endif /* HAVE_SSL */ 471