gdoid/src/gdoi_iec90_5.c

609 lines
20 KiB
C

/* $Id: gdoi_iec90_5.c,v 1.1.2.1 2011/12/12 20:43:47 bew Exp $ */
/* $Source: /nfs/cscbz/gdoi/gdoicvs/gdoi/src/Attic/gdoi_iec90_5.c,v $ */
/*
* The license applies to all software incorporated in the "Cisco GDOI reference
* implementation" except for those portions incorporating third party software
* specifically identified as being licensed under separate license.
*
*
* The Cisco Systems Public Software License, Version 1.0
* Copyright (c) 2011 Cisco Systems, Inc. All rights reserved.
* Subject to the following terms and conditions, Cisco Systems, Inc.,
* hereby grants you a worldwide, royalty-free, nonexclusive, license,
* subject to third party intellectual property claims, to create
* derivative works of the Licensed Code and to reproduce, display,
* perform, sublicense, distribute such Licensed Code and derivative works.
* All rights not expressly granted herein are reserved.
* 1. Redistributions of source code must retain the above
* copyright notice, this list of conditions and the following
* disclaimer.
* 2. Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials
* provided with the distribution.
* 3. The names Cisco and "Cisco GDOI reference implementation" must not
* be used to endorse or promote products derived from this software without
* prior written permission. For written permission, please contact
* opensource@cisco.com.
* 4. Products derived from this software may not be called
* "Cisco" or "Cisco GDOI reference implementation", nor may "Cisco" or
* "Cisco GDOI reference implementation" appear in
* their name, without prior written permission of Cisco Systems, Inc.
* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
* PURPOSE, TITLE AND NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT
* SHALL CISCO SYSTEMS, INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
* THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE. THIS LIMITATION OF LIABILITY SHALL NOT APPLY TO
* LIABILITY FOR DEATH OR PERSONAL INJURY RESULTING FROM SUCH
* PARTY'S NEGLIGENCE TO THE EXTENT APPLICABLE LAW PROHIBITS SUCH
* LIMITATION. SOME JURISDICTIONS DO NOT ALLOW THE EXCLUSION OR
* LIMITATION OF INCIDENTAL OR CONSEQUENTIAL DAMAGES, SO THAT
* EXCLUSION AND LIMITATION MAY NOT APPLY TO YOU. FURTHER, YOU
* AGREE THAT IN NO EVENT WILL CISCO'S LIABILITY UNDER OR RELATED TO
* THIS AGREEMENT EXCEED AMOUNT FIVE THOUSAND DOLLARS (US)
* (US$5,000).
*
* ====================================================================
* This software consists of voluntary contributions made by Cisco Systems,
* Inc. and many individuals on behalf of Cisco Systems, Inc. For more
* information on Cisco Systems, Inc., please see <http://www.cisco.com/>.
*
* This product includes software developed by Ericsson Radio Systems.
*/
/*
* The license applies to all software incorporated in the "Cisco GDOI reference
* implementation" except for those portions incorporating third party software
* specifically identified as being licensed under separate license.
*
*
* The Cisco Systems Public Software License, Version 1.0
* Copyright (c) 2001 Cisco Systems, Inc. All rights reserved.
* Subject to the following terms and conditions, Cisco Systems, Inc.,
* hereby grants you a worldwide, royalty-free, nonexclusive, license,
* subject to third party intellectual property claims, to create
* derivative works of the Licensed Code and to reproduce, display,
* perform, sublicense, distribute such Licensed Code and derivative works.
* All rights not expressly granted herein are reserved.
* 1. Redistributions of source code must retain the above
* copyright notice, this list of conditions and the following
* disclaimer.
* 2. Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials
* provided with the distribution.
* 3. The names Cisco and "Cisco GDOI reference implementation" must not
* be used to endorse or promote products derived from this software without
* prior written permission. For written permission, please contact
* opensource@cisco.com.
* 4. Products derived from this software may not be called
* "Cisco" or "Cisco GDOI reference implementation", nor may "Cisco" or
* "Cisco GDOI reference implementation" appear in
* their name, without prior written permission of Cisco Systems, Inc.
* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
* PURPOSE, TITLE AND NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT
* SHALL CISCO SYSTEMS, INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
* THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE. THIS LIMITATION OF LIABILITY SHALL NOT APPLY TO
* LIABILITY FOR DEATH OR PERSONAL INJURY RESULTING FROM SUCH
* PARTY'S NEGLIGENCE TO THE EXTENT APPLICABLE LAW PROHIBITS SUCH
* LIMITATION. SOME JURISDICTIONS DO NOT ALLOW THE EXCLUSION OR
* LIMITATION OF INCIDENTAL OR CONSEQUENTIAL DAMAGES, SO THAT
* EXCLUSION AND LIMITATION MAY NOT APPLY TO YOU. FURTHER, YOU
* AGREE THAT IN NO EVENT WILL CISCO'S LIABILITY UNDER OR RELATED TO
* THIS AGREEMENT EXCEED AMOUNT FIVE THOUSAND DOLLARS (US)
* (US$5,000).
*
* ====================================================================
* This software consists of voluntary contributions made by Cisco Systems,
* Inc. and many individuals on behalf of Cisco Systems, Inc. For more
* information on Cisco Systems, Inc., please see <http://www.cisco.com/>.
*
* This product includes software developed by Ericsson Radio Systems.
*/
#include <stdlib.h>
#include <string.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include "attribute.h"
#include "conf.h"
#include "connection.h"
#include "doi.h"
#include "exchange.h"
#include "hash.h"
#include "gdoi_phase2.h"
#include "log.h"
#include "message.h"
#include "prf.h"
#include "sa.h"
#include "transport.h"
#include "util.h"
#include "gdoi_fld.h"
#include "ipsec_num.h"
#include "gdoi_num.h"
#include "gdoi_iec90_5.h"
#include "iec90_5_num.h"
#include "iec90_5_fld.h"
#include "gdoi.h"
#include "gdoi_app_iec90_5_attr.h"
int
iec90_5_get_id (char *section, size_t *id_sz, u_int8_t **buf)
{
int oid_type;
char *oid, *address;
struct in_addr ip_addr;
size_t id_asn_sz, id_buf_sz;
u_int8_t *id_buf;
oid = conf_get_str (section, "OID");
oid_type = constant_value (iec90_5_id_cst, oid);
switch (oid_type)
{
case IEC90_5_ID_61850_UDP_ADDR_GOOSE:
address = conf_get_str (section, "Address");
if (!address)
{
log_print ("iec90_5_get_id: section %s has no \"Address\" tag",
section);
return -1;
}
if (!inet_aton (address, &ip_addr))
{
log_print ("iec90_5_get_id: invalid address %s in section %s",
section, address);
return -1;
}
break;
default:
log_print ("iec90_5_get_id: Unkonwn or Unsupported IEC90_5 OID: %d\n",
oid_type);
return -1;
}
/*
* Format ID payload. See Clause 11.4.2 ("Identification Paylod") of 90-5.
* NOTE: This doesn't actually match that clause -- needs work.
*/
id_asn_sz = strlen(OID_61850_UDP_ADDR_GOOSE);
id_buf_sz = IEC90_5_ID_SZ + id_asn_sz;
id_buf = calloc(1, id_buf_sz);
if (!id_buf) {
log_print ("iec90_5_get_id: Calloc failed for %d bytes\n", id_buf_sz);
return -1;
}
SET_IEC90_5_ID_ID(id_buf, 0xa1);
SET_IEC90_5_ID_PAYLOAD_LEN(id_buf, id_buf_sz);
SET_IEC90_5_ID_TAG(id_buf, 0x80);
SET_IEC90_5_ID_OID_LEN(id_buf, id_asn_sz);
memcpy(&id_buf[IEC90_5_ID_SZ], OID_61850_UDP_ADDR_GOOSE, id_asn_sz);
*buf = id_buf;
*id_sz = id_buf_sz;
return 0;
}
int
iec90_5_validate_id_information (u_int8_t *buf)
{
LOG_DBG ((LOG_MESSAGE, 40,
"iec90_5_validate_id_information: Got an IEC90-5 ID"));
/*
* The ID payload is so complicated that it probably warrants some good
* format validation here.
*/
return 0;
}
/*
* Key server side
* Find the TEK-specific policy for an IEC90-5 type TEK.
*/
int gdoi_iec90_5_set_policy (char *conf_field, struct message *msg,
struct exchange *sa_exchange, u_int8_t *id_gdoi,
u_int16_t id_gdoi_sz)
{
struct sa *sa;
struct proto *proto;
struct iec90_5_proto *iec_proto;
u_int8_t *iec90_5_id;
/*
* Find the sa. The last SA in the list was just created for our use.
*/
sa = TAILQ_LAST (&sa_exchange->sa_list, sa_head);
if (!sa)
{
log_error ("gdoi_iec90_5_set_policy: No sa's in list!");
goto bail_out;
}
/*
* Initialize the SA
*/
if (gdoi_setup_sa (sa, &proto, IPSEC_PROTO_IEC90_5, sizeof(struct iec90_5_proto)))
{
goto bail_out;
}
iec_proto = proto->data;
/*
* TEK will need to include the ID ASN.1 included in the 1st GDOI message.
* Note: Need to adjust the starting point of the macros to the start of
* the IEC90-5 specific ID data.
*/
iec90_5_id = id_gdoi + 8;
iec_proto->oid_sz = GET_IEC90_5_ID_OID_LEN(iec90_5_id);
iec_proto->oid = calloc(1, iec_proto->oid_sz);
if (!iec_proto->oid) {
log_error ("gdoi_iec90_5_set_policy: Malloc failed %d bytes.");
goto bail_out;
}
memcpy(iec_proto->oid, &iec90_5_id[IEC90_5_ID_SZ], iec_proto->oid_sz);
/*
* BEW: Hardcode policy for now. It shoud be read in from the configuration.
*/
iec_proto->auth_alg = GDOI_KEK_HASH_ALG_SHA;
iec_proto->auth_key_size = HMAC_SHA_LENGTH;
iec_proto->next_auth_alg = 0;
iec_proto->next_auth_key_size = 0;
/*
* BEW: Assume SPI is 1 byte.
* Also, just send key_id NOT next key_id for now.
*/
proto->spi_sz[0] = 1;
proto->spi[0] = malloc(proto->spi_sz[0]);
if (!proto->spi[0])
{
log_error ("gdoi_iec90_5_set_policy: malloc failure -- SPI (%d bytes)",
proto->spi_sz[0]);
goto bail_out;
}
/*
* Choose a random SPI
*
* Write the SPI length & SPI.
*/
getrandom(proto->spi[0], proto->spi_sz[0]);
iec_proto->auth_key = malloc(iec_proto->auth_key_size);
if (!iec_proto->auth_key)
{
log_print ("gdoi_iec90_5_set_policy: malloc failed: auth key (%d)",
iec_proto->auth_key_size);
goto bail_out;
}
getrandom(iec_proto->auth_key, iec_proto->auth_key_size);
return 0;
bail_out:
return -1;
}
int
gdoi_iec90_5_get_policy_from_sa (struct sa *sa, u_int8_t **ret_buf,
size_t *ret_buf_sz)
{
u_int8_t *iec90_5_tek_buf = 0;
u_int8_t *iec90_5_tek_p2_buf = 0;
size_t iec90_5_tek_sz;
struct proto *proto;
struct iec90_5_proto *iec_proto;
char keyid;
proto = TAILQ_FIRST (&sa->protos);
iec_proto = proto->data;
iec90_5_tek_sz = IEC90_5_TEK_P1_SZ + iec_proto->oid_sz + IEC90_5_TEK_P2_SZ;
iec90_5_tek_buf = calloc(1, iec90_5_tek_sz);
if (!iec90_5_tek_buf) {
log_print ("gdoi_iec90_5_get_policy_from_sa: Failed to get %d bytes for "
"IEC90-5 TEK payload", iec90_5_tek_sz);
return -1;
}
/*
* IEC90-5 paylaod (approximtely)
*/
SET_IEC90_5_TEK_P1_TAG(iec90_5_tek_buf, 0x80);
SET_IEC90_5_TEK_P1_OID_SZ(iec90_5_tek_buf, iec_proto->oid_sz);
memcpy(iec90_5_tek_buf+IEC90_5_TEK_P1_SZ, iec_proto->oid, iec_proto->oid_sz);
iec90_5_tek_p2_buf = iec90_5_tek_buf + IEC90_5_TEK_P1_SZ + iec_proto->oid_sz;
if (1 == proto->spi_sz[0]) {
keyid = *proto->spi[0];
SET_IEC90_5_TEK_P2_CUR_KEY_ID(iec90_5_tek_p2_buf, keyid);
} else {
log_print ("gdoi_iec90_5_get_policy_from_sa: Improper SPI size %d!",
proto->spi_sz[0]);
return -1;
}
/*
* NOTE: The same values below need to be sent in the KD paylaod!
*/
SET_IEC90_5_TEK_P2_LT_ID(iec90_5_tek_p2_buf, 1);
SET_IEC90_5_TEK_P2_LT_V(iec90_5_tek_p2_buf, 1);
SET_IEC90_5_TEK_P2_RES(iec90_5_tek_p2_buf, 0);
SET_IEC90_5_TEK_P2_LT(iec90_5_tek_p2_buf, 3600);
SET_IEC90_5_TEK_P2_AUTH_ALG_ID(iec90_5_tek_p2_buf, 5);
SET_IEC90_5_TEK_P2_AUTH_ALG(iec90_5_tek_p2_buf, 2);
SET_IEC90_5_TEK_P2_KEY_LEN(iec90_5_tek_p2_buf, iec_proto->auth_key_size);
/*
* I don't get how the AES bits work when HMAC is used so am omitting them.
* Also omitting the next key stuff.
*/
*ret_buf = iec90_5_tek_buf;
*ret_buf_sz = iec90_5_tek_sz;
return 0;
}
/*
* Group member side (decode & store TEK values) Decode the SRTP type TEK
* and stuff into the SA.
*/
int
gdoi_iec90_5_decode_tek (struct message *msg, struct sa *sa,
u_int8_t *iec90_5_tek, size_t iec90_5_tek_len,
int create_proto)
{
u_int8_t *iec90_5_p2_tek;
struct proto *proto = NULL;
struct iec90_5_proto *iec_proto = NULL;
u_int8_t tmp_1byte;
/*
* Validate the SA.
*/
if (!sa)
{
log_error ("group_decode_esp_tek: No sa's in list!");
goto clean_up;
}
if (create_proto)
{
if (gdoi_setup_sa (sa, &proto, IPSEC_PROTO_IEC90_5,
sizeof(struct iec90_5_proto)))
{
goto clean_up;
}
}
else
{
proto = TAILQ_LAST(&sa->protos, proto_head);
}
/*
* Stuff the SRTP policy in the proto structure. (Can't use sa->data because
* that is initialized in sa_create(). sa->data is unused for SRTP.)
*/
iec_proto = (struct iec90_5_proto *) proto->data;
/*
* Process 1st part of TEK (OID)
*/
tmp_1byte = GET_IEC90_5_TEK_P1_TAG(iec90_5_tek);
if (0x80 != tmp_1byte) {
log_print ("gdoi_iec90_5_decode_tek: Wrong TEK ID %d\n", tmp_1byte);
goto clean_up;
}
iec_proto->oid_sz = GET_IEC90_5_TEK_P1_OID_SZ(iec90_5_tek);
iec_proto->oid = calloc(1, iec_proto->oid_sz);
if (!iec_proto->oid) {
log_print ("gdoi_iec90_5_decode_tek: calloc failed for OID size (%d)",
iec_proto->oid_sz);
goto clean_up;
}
memcpy(iec_proto->oid, iec90_5_tek+IEC90_5_TEK_P1_SZ, iec_proto->oid_sz);
/*
* Process 2nd part of TEK
*/
/* SPI */
iec90_5_p2_tek = iec90_5_tek + IEC90_5_TEK_P1_SZ + iec_proto->oid_sz;
proto->spi_sz[0] = 1; /* Hard code to match TEK */
proto->spi[0] = malloc(proto->spi_sz[0]);
if (!proto->spi[0])
{
log_error ("gdoi_iec90_5_decode_tek: malloc failure -- SPI (%d bytes)",
proto->spi_sz[0]);
goto clean_up;
}
*proto->spi[0] = GET_IEC90_5_TEK_P2_CUR_KEY_ID(iec90_5_p2_tek);
log_print(" SPI found (SA) %u (%01#x) for sa %#x",
*proto->spi[0], *proto->spi[0], sa);
/* Lifetime & Reserved byte */
tmp_1byte = GET_IEC90_5_TEK_P2_LT_ID(iec90_5_p2_tek);
if (1 != tmp_1byte) {
log_print ("gdoi_iec90_5_decode_tek: Wrong LT ID %d\n", tmp_1byte);
goto clean_up;
}
tmp_1byte = GET_IEC90_5_TEK_P2_RES(iec90_5_p2_tek);
if (0 != tmp_1byte) {
log_print ("gdoi_iec90_5_decode_tek: Wrong Reserved byte value %d\n",
tmp_1byte);
goto clean_up;
}
tmp_1byte = GET_IEC90_5_TEK_P2_LT_V(iec90_5_p2_tek);
if (1 != tmp_1byte) {
log_print ("gdoi_iec90_5_decode_tek: Wrong LT V %d\n", tmp_1byte);
goto clean_up;
}
iec_proto->lifetime_secs = GET_IEC90_5_TEK_P2_LT(iec90_5_p2_tek);
/* Authentication values */
tmp_1byte = GET_IEC90_5_TEK_P2_AUTH_ALG_ID(iec90_5_p2_tek);
if (5 != tmp_1byte) {
log_print ("gdoi_iec90_5_decode_tek: Wrong Auth value %d\n", tmp_1byte);
goto clean_up;
}
iec_proto->auth_alg = GET_IEC90_5_TEK_P2_AUTH_ALG(iec90_5_p2_tek);
iec_proto->auth_key_size = GET_IEC90_5_TEK_P2_KEY_LEN(iec90_5_p2_tek);
return 0;
clean_up:
if (proto)
{
proto_free(proto);
}
return -1;
}
/*
* Translate keys from the IEC90-5 proto into a generic structure
*/
int
gdoi_iec90_5_get_tek_keys (struct gdoi_kd_decode_arg *keys, struct proto *proto)
{
struct iec90_5_proto *iec_proto= (struct iec90_5_proto *) proto->data;
u_int8_t *kd_buf;
u_int32_t kd_sz;
/*
* Build a private KD attribute for IEC90-5.
*/
if (!iec_proto->auth_key_size) {
log_print ("gdoi_iec90_5_get_tek_keys: Warning: No keys to send!");
return 0;
}
kd_sz = IEC90_5_KD_SZ + iec_proto->auth_key_size;
kd_buf = calloc(1, kd_sz);
if (!kd_buf) {
log_print ("gdoi_iec90_5_get_tek_keys: Failed to get %d bytes for "
"IEC90-5 KD payload", kd_sz);
return -1;
}
/*
* Note: Most or all of these hard coded values should have come from policy
* stored in iec_proto.
*/
SET_IEC90_5_KD_LT_ID(kd_buf,1);
SET_IEC90_5_KD_LT_V(kd_buf,1);
SET_IEC90_5_KD_RES(kd_buf,0);
SET_IEC90_5_KD_LT(kd_buf, 3600);
SET_IEC90_5_KD_AUTH_ALG_ID(kd_buf, 5);
SET_IEC90_5_KD_AUTH_ALG(kd_buf, 2);
SET_IEC90_5_KD_KEY_LEN(kd_buf, iec_proto->auth_key_size);
memcpy(kd_buf + IEC90_5_KD_SZ, iec_proto->auth_key, iec_proto->auth_key_size);
keys->custom_kd_payload = kd_buf;
keys->custom_kd_payload_sz = kd_sz;
/* I have not idea which value to use for the payload type */
keys->custom_kd_payload_type = IEC90_5_KD_61850_ETHERENT_GOOSE_OR_SV;
return 0;
}
/*
* Group member side
* Validate and install keys gotten from the KD in the iec_proto structure.
*/
int
gdoi_iec90_5_install_keys (struct proto *proto, struct gdoi_kd_decode_arg *keys)
{
struct iec90_5_proto *iec_proto;
u_int8_t *kd_buf;
kd_buf = keys->custom_kd_payload;
if (proto->proto != IPSEC_PROTO_IEC90_5)
{
log_error ("gdoi_iec90_5_install_keys: IEC90_5 SA expected, got %d",
proto->proto);
return -1;
}
iec_proto = (struct iec90_5_proto *) proto->data;
if (!iec_proto)
{
log_error ("gdoi_iec90_5_install_keys: IEC90_5 SA TEK data missing");
return -1;
}
if (GET_IEC90_5_KD_KEY_LEN(kd_buf) != iec_proto->auth_key_size) {
log_print ("gdoi_iec90_5_install_keys: Auth key size doesn't match"
"key size sent in TEK");
return -1;
}
iec_proto->auth_key = malloc(iec_proto->auth_key_size);
if (!iec_proto->auth_key)
{
log_print ("gdoi_iec90_5_get_policy: malloc failed: auth key (%d)",
iec_proto->auth_key_size);
return -1;
}
memcpy(iec_proto->auth_key, kd_buf + IEC90_5_KD_SZ, iec_proto->auth_key_size);
/* No need to save policy already sent in the TEK payload */
return 0;
}
u_int8_t *
gdoi_iec90_5_add_attributes (u_int8_t *attr, struct sa *sa)
{
struct proto *proto = NULL;
struct iec90_5_proto *iec_proto = NULL;
proto = TAILQ_LAST(&sa->protos, proto_head);
iec_proto = (struct iec90_5_proto *) proto->data;
attr = attribute_set_var(attr, IEC90_5_OID, iec_proto->oid,
iec_proto->oid_sz);
attr = attribute_set_var(attr, IEC90_5_LIFETIME_SECS,
(u_int8_t *)&iec_proto->lifetime_secs,
sizeof(iec_proto->lifetime_secs));
attr = attribute_set_basic(attr, IEC90_5_KEYID, *proto->spi[0]);
attr = attribute_set_basic(attr, IEC90_5_AUTH_ALG, iec_proto->auth_alg);
attr = attribute_set_basic(attr, IEC90_5_AUTH_KEY_SIZE,
iec_proto->auth_key_size);
if (!iec_proto->auth_key)
{
log_print ("gdoi_iec90_5_add_attributes: Auth key missing!\n");
}
else
{
attr = attribute_set_var (attr, IEC90_5_AUTH_KEY, iec_proto->auth_key,
iec_proto->auth_key_size);
}
return attr;
}