pubkey-authenticator: Add support for authentication with PPK
This commit is contained in:
@@ -56,6 +56,16 @@ struct private_pubkey_authenticator_t {
|
|||||||
* Reserved bytes of ID payload
|
* Reserved bytes of ID payload
|
||||||
*/
|
*/
|
||||||
char reserved[3];
|
char reserved[3];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* PPK to use
|
||||||
|
*/
|
||||||
|
chunk_t ppk;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add a NO_PPK_AUTH notify
|
||||||
|
*/
|
||||||
|
bool no_ppk_auth;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -203,18 +213,43 @@ CALLBACK(destroy_scheme, void,
|
|||||||
signature_params_destroy(params);
|
signature_params_destroy(params);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds the given auth data to the message, either in an AUTH payload or
|
||||||
|
* a NO_PPK_AUTH notify.
|
||||||
|
*
|
||||||
|
* The data is freed.
|
||||||
|
*/
|
||||||
|
static void add_auth_to_message(message_t *message, auth_method_t method,
|
||||||
|
chunk_t data, bool notify)
|
||||||
|
{
|
||||||
|
auth_payload_t *auth_payload;
|
||||||
|
|
||||||
|
if (notify)
|
||||||
|
{
|
||||||
|
message->add_notify(message, FALSE, NO_PPK_AUTH, data);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
auth_payload = auth_payload_create();
|
||||||
|
auth_payload->set_auth_method(auth_payload, method);
|
||||||
|
auth_payload->set_data(auth_payload, data);
|
||||||
|
message->add_payload(message, (payload_t*)auth_payload);
|
||||||
|
}
|
||||||
|
chunk_free(&data);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a signature using RFC 7427 signature authentication
|
* Create a signature using RFC 7427 signature authentication
|
||||||
*/
|
*/
|
||||||
static status_t sign_signature_auth(private_pubkey_authenticator_t *this,
|
static status_t sign_signature_auth(private_pubkey_authenticator_t *this,
|
||||||
auth_cfg_t *auth, private_key_t *private,
|
auth_cfg_t *auth, private_key_t *private,
|
||||||
identification_t *id, chunk_t *auth_data)
|
identification_t *id, message_t *message)
|
||||||
{
|
{
|
||||||
enumerator_t *enumerator;
|
enumerator_t *enumerator;
|
||||||
keymat_v2_t *keymat;
|
keymat_v2_t *keymat;
|
||||||
signature_params_t *params = NULL;
|
signature_params_t *params = NULL;
|
||||||
array_t *schemes;
|
array_t *schemes;
|
||||||
chunk_t octets = chunk_empty;
|
chunk_t octets = chunk_empty, auth_data;
|
||||||
status_t status = FAILED;
|
status_t status = FAILED;
|
||||||
|
|
||||||
keymat = (keymat_v2_t*)this->ike_sa->get_keymat(this->ike_sa);
|
keymat = (keymat_v2_t*)this->ike_sa->get_keymat(this->ike_sa);
|
||||||
@@ -228,25 +263,45 @@ static status_t sign_signature_auth(private_pubkey_authenticator_t *this,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (keymat->get_auth_octets(keymat, FALSE, this->ike_sa_init, this->nonce,
|
if (keymat->get_auth_octets(keymat, FALSE, this->ike_sa_init, this->nonce,
|
||||||
chunk_empty, id, this->reserved, &octets,
|
this->ppk, id, this->reserved, &octets, schemes))
|
||||||
schemes))
|
|
||||||
{
|
{
|
||||||
enumerator = array_create_enumerator(schemes);
|
enumerator = array_create_enumerator(schemes);
|
||||||
while (enumerator->enumerate(enumerator, ¶ms))
|
while (enumerator->enumerate(enumerator, ¶ms))
|
||||||
{
|
{
|
||||||
if (private->sign(private, params->scheme, params->params, octets,
|
if (!private->sign(private, params->scheme, params->params, octets,
|
||||||
auth_data) &&
|
&auth_data) ||
|
||||||
build_signature_auth_data(auth_data, params))
|
!build_signature_auth_data(&auth_data, params))
|
||||||
{
|
|
||||||
status = SUCCESS;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
{
|
||||||
DBG2(DBG_IKE, "unable to create %N signature for %N key",
|
DBG2(DBG_IKE, "unable to create %N signature for %N key",
|
||||||
signature_scheme_names, params->scheme, key_type_names,
|
signature_scheme_names, params->scheme, key_type_names,
|
||||||
private->get_type(private));
|
private->get_type(private));
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
|
add_auth_to_message(message, AUTH_DS, auth_data, FALSE);
|
||||||
|
status = SUCCESS;
|
||||||
|
|
||||||
|
if (this->no_ppk_auth)
|
||||||
|
{
|
||||||
|
chunk_free(&octets);
|
||||||
|
|
||||||
|
if (keymat->get_auth_octets(keymat, FALSE, this->ike_sa_init,
|
||||||
|
this->nonce, chunk_empty, id,
|
||||||
|
this->reserved, &octets, schemes) &&
|
||||||
|
private->sign(private, params->scheme, params->params,
|
||||||
|
octets, &auth_data) &&
|
||||||
|
build_signature_auth_data(&auth_data, params))
|
||||||
|
{
|
||||||
|
add_auth_to_message(message, AUTH_DS, auth_data, TRUE);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
DBG2(DBG_IKE, "unable to create %N signature for %N key "
|
||||||
|
"without PPK", signature_scheme_names, params->scheme,
|
||||||
|
key_type_names, private->get_type(private));
|
||||||
|
status = FAILED;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
enumerator->destroy(enumerator);
|
enumerator->destroy(enumerator);
|
||||||
}
|
}
|
||||||
@@ -281,8 +336,8 @@ static status_t sign_signature_auth(private_pubkey_authenticator_t *this,
|
|||||||
* keymat).
|
* keymat).
|
||||||
*/
|
*/
|
||||||
static bool get_auth_octets_scheme(private_pubkey_authenticator_t *this,
|
static bool get_auth_octets_scheme(private_pubkey_authenticator_t *this,
|
||||||
bool verify, identification_t *id,
|
bool verify, identification_t *id, chunk_t ppk,
|
||||||
chunk_t *octets, signature_params_t **scheme)
|
chunk_t *octets, signature_params_t **scheme)
|
||||||
{
|
{
|
||||||
keymat_v2_t *keymat;
|
keymat_v2_t *keymat;
|
||||||
array_t *schemes;
|
array_t *schemes;
|
||||||
@@ -293,7 +348,7 @@ static bool get_auth_octets_scheme(private_pubkey_authenticator_t *this,
|
|||||||
|
|
||||||
keymat = (keymat_v2_t*)this->ike_sa->get_keymat(this->ike_sa);
|
keymat = (keymat_v2_t*)this->ike_sa->get_keymat(this->ike_sa);
|
||||||
if (keymat->get_auth_octets(keymat, verify, this->ike_sa_init, this->nonce,
|
if (keymat->get_auth_octets(keymat, verify, this->ike_sa_init, this->nonce,
|
||||||
chunk_empty, id, this->reserved, octets,
|
ppk, id, this->reserved, octets,
|
||||||
schemes) &&
|
schemes) &&
|
||||||
array_remove(schemes, 0, scheme))
|
array_remove(schemes, 0, scheme))
|
||||||
{
|
{
|
||||||
@@ -312,19 +367,19 @@ static bool get_auth_octets_scheme(private_pubkey_authenticator_t *this,
|
|||||||
*/
|
*/
|
||||||
static status_t sign_classic(private_pubkey_authenticator_t *this,
|
static status_t sign_classic(private_pubkey_authenticator_t *this,
|
||||||
auth_cfg_t *auth, private_key_t *private,
|
auth_cfg_t *auth, private_key_t *private,
|
||||||
identification_t *id, auth_method_t *auth_method,
|
identification_t *id, message_t *message)
|
||||||
chunk_t *auth_data)
|
|
||||||
{
|
{
|
||||||
signature_scheme_t scheme;
|
signature_scheme_t scheme;
|
||||||
signature_params_t *params;
|
signature_params_t *params;
|
||||||
chunk_t octets = chunk_empty;
|
auth_method_t auth_method = AUTH_NONE;
|
||||||
|
chunk_t octets = chunk_empty, auth_data;
|
||||||
status_t status = FAILED;
|
status_t status = FAILED;
|
||||||
|
|
||||||
switch (private->get_type(private))
|
switch (private->get_type(private))
|
||||||
{
|
{
|
||||||
case KEY_RSA:
|
case KEY_RSA:
|
||||||
scheme = SIGN_RSA_EMSA_PKCS1_SHA1;
|
scheme = SIGN_RSA_EMSA_PKCS1_SHA1;
|
||||||
*auth_method = AUTH_RSA;
|
auth_method = AUTH_RSA;
|
||||||
break;
|
break;
|
||||||
case KEY_ECDSA:
|
case KEY_ECDSA:
|
||||||
/* deduct the signature scheme from the keysize */
|
/* deduct the signature scheme from the keysize */
|
||||||
@@ -332,15 +387,15 @@ static status_t sign_classic(private_pubkey_authenticator_t *this,
|
|||||||
{
|
{
|
||||||
case 256:
|
case 256:
|
||||||
scheme = SIGN_ECDSA_256;
|
scheme = SIGN_ECDSA_256;
|
||||||
*auth_method = AUTH_ECDSA_256;
|
auth_method = AUTH_ECDSA_256;
|
||||||
break;
|
break;
|
||||||
case 384:
|
case 384:
|
||||||
scheme = SIGN_ECDSA_384;
|
scheme = SIGN_ECDSA_384;
|
||||||
*auth_method = AUTH_ECDSA_384;
|
auth_method = AUTH_ECDSA_384;
|
||||||
break;
|
break;
|
||||||
case 521:
|
case 521:
|
||||||
scheme = SIGN_ECDSA_521;
|
scheme = SIGN_ECDSA_521;
|
||||||
*auth_method = AUTH_ECDSA_521;
|
auth_method = AUTH_ECDSA_521;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
DBG1(DBG_IKE, "%d bit ECDSA private key size not supported",
|
DBG1(DBG_IKE, "%d bit ECDSA private key size not supported",
|
||||||
@@ -357,17 +412,34 @@ static status_t sign_classic(private_pubkey_authenticator_t *this,
|
|||||||
INIT(params,
|
INIT(params,
|
||||||
.scheme = scheme,
|
.scheme = scheme,
|
||||||
);
|
);
|
||||||
if (get_auth_octets_scheme(this, FALSE, id, &octets, ¶ms) &&
|
if (get_auth_octets_scheme(this, FALSE, id, this->ppk, &octets, ¶ms) &&
|
||||||
private->sign(private, params->scheme, NULL, octets, auth_data))
|
private->sign(private, params->scheme, NULL, octets, &auth_data))
|
||||||
{
|
{
|
||||||
|
add_auth_to_message(message, auth_method, auth_data, FALSE);
|
||||||
status = SUCCESS;
|
status = SUCCESS;
|
||||||
|
|
||||||
|
if (this->no_ppk_auth)
|
||||||
|
{
|
||||||
|
chunk_free(&octets);
|
||||||
|
if (get_auth_octets_scheme(this, FALSE, id, chunk_empty, &octets,
|
||||||
|
¶ms) &&
|
||||||
|
private->sign(private, params->scheme, NULL, octets,
|
||||||
|
&auth_data))
|
||||||
|
{
|
||||||
|
add_auth_to_message(message, auth_method, auth_data, TRUE);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
status = FAILED;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (params)
|
if (params)
|
||||||
{
|
{
|
||||||
signature_params_destroy(params);
|
signature_params_destroy(params);
|
||||||
}
|
}
|
||||||
DBG1(DBG_IKE, "authentication of '%Y' (myself) with %N %s", id,
|
DBG1(DBG_IKE, "authentication of '%Y' (myself) with %N %s", id,
|
||||||
auth_method_names, *auth_method,
|
auth_method_names, auth_method,
|
||||||
status == SUCCESS ? "successful" : "failed");
|
status == SUCCESS ? "successful" : "failed");
|
||||||
chunk_free(&octets);
|
chunk_free(&octets);
|
||||||
return status;
|
return status;
|
||||||
@@ -379,10 +451,7 @@ METHOD(authenticator_t, build, status_t,
|
|||||||
private_key_t *private;
|
private_key_t *private;
|
||||||
identification_t *id;
|
identification_t *id;
|
||||||
auth_cfg_t *auth;
|
auth_cfg_t *auth;
|
||||||
chunk_t auth_data;
|
|
||||||
status_t status;
|
status_t status;
|
||||||
auth_payload_t *auth_payload;
|
|
||||||
auth_method_t auth_method = AUTH_NONE;
|
|
||||||
|
|
||||||
id = this->ike_sa->get_my_id(this->ike_sa);
|
id = this->ike_sa->get_my_id(this->ike_sa);
|
||||||
auth = this->ike_sa->get_auth_cfg(this->ike_sa, TRUE);
|
auth = this->ike_sa->get_auth_cfg(this->ike_sa, TRUE);
|
||||||
@@ -395,24 +464,13 @@ METHOD(authenticator_t, build, status_t,
|
|||||||
|
|
||||||
if (this->ike_sa->supports_extension(this->ike_sa, EXT_SIGNATURE_AUTH))
|
if (this->ike_sa->supports_extension(this->ike_sa, EXT_SIGNATURE_AUTH))
|
||||||
{
|
{
|
||||||
auth_method = AUTH_DS;
|
status = sign_signature_auth(this, auth, private, id, message);
|
||||||
status = sign_signature_auth(this, auth, private, id, &auth_data);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
status = sign_classic(this, auth, private, id, &auth_method,
|
status = sign_classic(this, auth, private, id, message);
|
||||||
&auth_data);
|
|
||||||
}
|
}
|
||||||
private->destroy(private);
|
private->destroy(private);
|
||||||
|
|
||||||
if (status == SUCCESS)
|
|
||||||
{
|
|
||||||
auth_payload = auth_payload_create();
|
|
||||||
auth_payload->set_auth_method(auth_payload, auth_method);
|
|
||||||
auth_payload->set_data(auth_payload, auth_data);
|
|
||||||
chunk_free(&auth_data);
|
|
||||||
message->add_payload(message, (payload_t*)auth_payload);
|
|
||||||
}
|
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -445,6 +503,7 @@ METHOD(authenticator_t, process, status_t,
|
|||||||
public_key_t *public;
|
public_key_t *public;
|
||||||
auth_method_t auth_method;
|
auth_method_t auth_method;
|
||||||
auth_payload_t *auth_payload;
|
auth_payload_t *auth_payload;
|
||||||
|
notify_payload_t *notify;
|
||||||
chunk_t auth_data, octets;
|
chunk_t auth_data, octets;
|
||||||
identification_t *id;
|
identification_t *id;
|
||||||
auth_cfg_t *auth, *current_auth;
|
auth_cfg_t *auth, *current_auth;
|
||||||
@@ -460,9 +519,21 @@ METHOD(authenticator_t, process, status_t,
|
|||||||
{
|
{
|
||||||
return FAILED;
|
return FAILED;
|
||||||
}
|
}
|
||||||
INIT(params);
|
|
||||||
auth_method = auth_payload->get_auth_method(auth_payload);
|
auth_method = auth_payload->get_auth_method(auth_payload);
|
||||||
auth_data = auth_payload->get_data(auth_payload);
|
auth_data = auth_payload->get_data(auth_payload);
|
||||||
|
|
||||||
|
if (this->ike_sa->supports_extension(this->ike_sa, EXT_PPK) &&
|
||||||
|
!this->ppk.ptr)
|
||||||
|
{ /* look for a NO_PPK_AUTH notify if we have no PPK */
|
||||||
|
notify = message->get_notify(message, NO_PPK_AUTH);
|
||||||
|
if (notify)
|
||||||
|
{
|
||||||
|
DBG1(DBG_IKE, "no PPK available, using NO_PPK_AUTH notify");
|
||||||
|
auth_data = notify->get_notification_data(notify);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
INIT(params);
|
||||||
switch (auth_method)
|
switch (auth_method)
|
||||||
{
|
{
|
||||||
case AUTH_RSA:
|
case AUTH_RSA:
|
||||||
@@ -492,7 +563,7 @@ METHOD(authenticator_t, process, status_t,
|
|||||||
return INVALID_ARG;
|
return INVALID_ARG;
|
||||||
}
|
}
|
||||||
id = this->ike_sa->get_other_id(this->ike_sa);
|
id = this->ike_sa->get_other_id(this->ike_sa);
|
||||||
if (!get_auth_octets_scheme(this, TRUE, id, &octets, ¶ms))
|
if (!get_auth_octets_scheme(this, TRUE, id, this->ppk, &octets, ¶ms))
|
||||||
{
|
{
|
||||||
return FAILED;
|
return FAILED;
|
||||||
}
|
}
|
||||||
@@ -552,6 +623,13 @@ METHOD(authenticator_t, process, status_t,
|
|||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
METHOD(authenticator_t, use_ppk, void,
|
||||||
|
private_pubkey_authenticator_t *this, chunk_t ppk, bool no_ppk_auth)
|
||||||
|
{
|
||||||
|
this->ppk = ppk;
|
||||||
|
this->no_ppk_auth = no_ppk_auth;
|
||||||
|
}
|
||||||
|
|
||||||
METHOD(authenticator_t, destroy, void,
|
METHOD(authenticator_t, destroy, void,
|
||||||
private_pubkey_authenticator_t *this)
|
private_pubkey_authenticator_t *this)
|
||||||
{
|
{
|
||||||
@@ -572,6 +650,7 @@ pubkey_authenticator_t *pubkey_authenticator_create_builder(ike_sa_t *ike_sa,
|
|||||||
.authenticator = {
|
.authenticator = {
|
||||||
.build = _build,
|
.build = _build,
|
||||||
.process = (void*)return_failed,
|
.process = (void*)return_failed,
|
||||||
|
.use_ppk = _use_ppk,
|
||||||
.is_mutual = (void*)return_false,
|
.is_mutual = (void*)return_false,
|
||||||
.destroy = _destroy,
|
.destroy = _destroy,
|
||||||
},
|
},
|
||||||
@@ -599,6 +678,7 @@ pubkey_authenticator_t *pubkey_authenticator_create_verifier(ike_sa_t *ike_sa,
|
|||||||
.authenticator = {
|
.authenticator = {
|
||||||
.build = (void*)return_failed,
|
.build = (void*)return_failed,
|
||||||
.process = _process,
|
.process = _process,
|
||||||
|
.use_ppk = _use_ppk,
|
||||||
.is_mutual = (void*)return_false,
|
.is_mutual = (void*)return_false,
|
||||||
.destroy = _destroy,
|
.destroy = _destroy,
|
||||||
},
|
},
|
||||||
|
|||||||
Reference in New Issue
Block a user