streamlined output from get_validity()
This commit is contained in:
@@ -951,13 +951,13 @@ static bool check_certificate(private_credential_manager_t *this,
|
|||||||
if (!subject->get_validity(subject, NULL, ¬_before, ¬_after))
|
if (!subject->get_validity(subject, NULL, ¬_before, ¬_after))
|
||||||
{
|
{
|
||||||
DBG1(DBG_CFG, "subject certificate invalid (valid from %T to %T)",
|
DBG1(DBG_CFG, "subject certificate invalid (valid from %T to %T)",
|
||||||
¬_before, TRUE, ¬_after, TRUE);
|
¬_before, FALSE, ¬_after, FALSE);
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
if (!issuer->get_validity(issuer, NULL, ¬_before, ¬_after))
|
if (!issuer->get_validity(issuer, NULL, ¬_before, ¬_after))
|
||||||
{
|
{
|
||||||
DBG1(DBG_CFG, "issuer certificate invalid (valid from %T to %T)",
|
DBG1(DBG_CFG, "issuer certificate invalid (valid from %T to %T)",
|
||||||
¬_before, TRUE, ¬_after, TRUE);
|
¬_before, FALSE, ¬_after, FALSE);
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
if (issuer->get_type(issuer) == CERT_X509 &&
|
if (issuer->get_type(issuer) == CERT_X509 &&
|
||||||
|
|||||||
@@ -798,16 +798,8 @@ static private_x509_ac_t* get_ref(private_x509_ac_t *this)
|
|||||||
static bool get_validity(private_x509_ac_t *this, time_t *when,
|
static bool get_validity(private_x509_ac_t *this, time_t *when,
|
||||||
time_t *not_before, time_t *not_after)
|
time_t *not_before, time_t *not_after)
|
||||||
{
|
{
|
||||||
time_t t;
|
time_t t = when ? *when : time(NULL);
|
||||||
|
|
||||||
if (when)
|
|
||||||
{
|
|
||||||
t = *when;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
t = time(NULL);
|
|
||||||
}
|
|
||||||
if (not_before)
|
if (not_before)
|
||||||
{
|
{
|
||||||
*not_before = this->notBefore;
|
*not_before = this->notBefore;
|
||||||
@@ -816,19 +808,7 @@ static bool get_validity(private_x509_ac_t *this, time_t *when,
|
|||||||
{
|
{
|
||||||
*not_after = this->notAfter;
|
*not_after = this->notAfter;
|
||||||
}
|
}
|
||||||
if (t < this->notBefore)
|
return (t >= this->notBefore && t <= this->notAfter);
|
||||||
{
|
|
||||||
DBG1("attribute certificate is not valid before %T",
|
|
||||||
this->notBefore, TRUE);
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
if (t > this->notAfter)
|
|
||||||
{
|
|
||||||
DBG1("attribute certificate expired on %T",
|
|
||||||
this->notAfter, TRUE);
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
return TRUE;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -844,7 +824,7 @@ static bool is_newer(private_x509_ac_t *this, ac_t *that)
|
|||||||
this_cert->get_validity(this_cert, &now, &this_update, NULL);
|
this_cert->get_validity(this_cert, &now, &this_update, NULL);
|
||||||
that_cert->get_validity(that_cert, &now, &that_update, NULL);
|
that_cert->get_validity(that_cert, &now, &that_update, NULL);
|
||||||
new = this_update > that_update;
|
new = this_update > that_update;
|
||||||
DBG1(" attr cert from %T is %s - existing attr_cert from %T %s",
|
DBG1(" attr cert from %T is %s - existing attr cert from %T %s",
|
||||||
&this_update, FALSE, new ? "newer":"not newer",
|
&this_update, FALSE, new ? "newer":"not newer",
|
||||||
&that_update, FALSE, new ? "replaced":"retained");
|
&that_update, FALSE, new ? "replaced":"retained");
|
||||||
return new;
|
return new;
|
||||||
|
|||||||
@@ -458,16 +458,8 @@ static private_x509_crl_t* get_ref(private_x509_crl_t *this)
|
|||||||
static bool get_validity(private_x509_crl_t *this, time_t *when,
|
static bool get_validity(private_x509_crl_t *this, time_t *when,
|
||||||
time_t *not_before, time_t *not_after)
|
time_t *not_before, time_t *not_after)
|
||||||
{
|
{
|
||||||
time_t t;
|
time_t t = when ? *when : time(NULL);
|
||||||
|
|
||||||
if (when)
|
|
||||||
{
|
|
||||||
t = *when;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
t = time(NULL);
|
|
||||||
}
|
|
||||||
if (not_before)
|
if (not_before)
|
||||||
{
|
{
|
||||||
*not_before = this->thisUpdate;
|
*not_before = this->thisUpdate;
|
||||||
|
|||||||
@@ -748,16 +748,8 @@ static public_key_t* get_public_key(private_x509_ocsp_response_t *this)
|
|||||||
static bool get_validity(private_x509_ocsp_response_t *this, time_t *when,
|
static bool get_validity(private_x509_ocsp_response_t *this, time_t *when,
|
||||||
time_t *not_before, time_t *not_after)
|
time_t *not_before, time_t *not_after)
|
||||||
{
|
{
|
||||||
time_t t;
|
time_t t = when ? *when : time(NULL);
|
||||||
|
|
||||||
if (when == NULL)
|
|
||||||
{
|
|
||||||
t = time(NULL);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
t = *when;
|
|
||||||
}
|
|
||||||
if (not_before)
|
if (not_before)
|
||||||
{
|
{
|
||||||
*not_before = this->producedAt;
|
*not_before = this->producedAt;
|
||||||
|
|||||||
+4
-2
@@ -158,7 +158,7 @@ bool verify_x509acert(x509acert_t *x509ac, bool strict)
|
|||||||
chunk_t issuer_dn = issuer->get_encoding(issuer);
|
chunk_t issuer_dn = issuer->get_encoding(issuer);
|
||||||
chunk_t authKeyID = ac->get_authKeyIdentifier(ac);
|
chunk_t authKeyID = ac->get_authKeyIdentifier(ac);
|
||||||
x509cert_t *aacert;
|
x509cert_t *aacert;
|
||||||
time_t valid_until;
|
time_t notBefore, valid_until;
|
||||||
|
|
||||||
DBG(DBG_CONTROL,
|
DBG(DBG_CONTROL,
|
||||||
DBG_log("holder: '%Y'", subject);
|
DBG_log("holder: '%Y'", subject);
|
||||||
@@ -167,10 +167,12 @@ bool verify_x509acert(x509acert_t *x509ac, bool strict)
|
|||||||
|
|
||||||
if (!cert_ac->get_validity(cert_ac, NULL, NULL, &valid_until))
|
if (!cert_ac->get_validity(cert_ac, NULL, NULL, &valid_until))
|
||||||
{
|
{
|
||||||
|
plog("attribute certificate is invalid (valid from %T to %T)",
|
||||||
|
¬Before, FALSE, &valid_until, FALSE);
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
DBG(DBG_CONTROL,
|
DBG(DBG_CONTROL,
|
||||||
DBG_log("attribute certificate is valid until %T", &valid_until, TRUE)
|
DBG_log("attribute certificate is valid until %T", &valid_until, FALSE)
|
||||||
)
|
)
|
||||||
|
|
||||||
lock_authcert_list("verify_x509acert");
|
lock_authcert_list("verify_x509acert");
|
||||||
|
|||||||
@@ -717,8 +717,6 @@ static void load_end_certificate(char *filename, struct end *dst)
|
|||||||
|
|
||||||
if (valid_cert)
|
if (valid_cert)
|
||||||
{
|
{
|
||||||
err_t ugh = NULL;
|
|
||||||
|
|
||||||
switch (cert.type)
|
switch (cert.type)
|
||||||
{
|
{
|
||||||
case CERT_PGP:
|
case CERT_PGP:
|
||||||
@@ -738,20 +736,18 @@ static void load_end_certificate(char *filename, struct end *dst)
|
|||||||
select_x509cert_id(cert.u.x509, &dst->id);
|
select_x509cert_id(cert.u.x509, &dst->id);
|
||||||
|
|
||||||
if (cached_cert)
|
if (cached_cert)
|
||||||
|
{
|
||||||
dst->cert = cert;
|
dst->cert = cert;
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
time_t valid_until = 0;
|
certificate_t *certificate = cert.u.x509->cert;
|
||||||
|
|
||||||
/* check validity of cert */
|
if (!certificate->get_validity(certificate, NULL, NULL, &valid_until))
|
||||||
ugh = check_validity(cert.u.x509, &valid_until);
|
|
||||||
if (ugh != NULL)
|
|
||||||
{
|
{
|
||||||
plog(" %s", ugh);
|
|
||||||
free_x509cert(cert.u.x509);
|
free_x509cert(cert.u.x509);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
DBG(DBG_CONTROL,
|
DBG(DBG_CONTROL,
|
||||||
DBG_log("certificate is valid")
|
DBG_log("certificate is valid")
|
||||||
)
|
)
|
||||||
|
|||||||
+17
-17
@@ -414,7 +414,7 @@ cert_status_t verify_by_crl(const x509cert_t *cert, time_t *until,
|
|||||||
crl_t *crl = (crl_t*)cert_crl;
|
crl_t *crl = (crl_t*)cert_crl;
|
||||||
chunk_t authKeyID = crl->get_authKeyIdentifier(crl);
|
chunk_t authKeyID = crl->get_authKeyIdentifier(crl);
|
||||||
x509cert_t *issuer_cert;
|
x509cert_t *issuer_cert;
|
||||||
bool valid;
|
bool trusted, valid;
|
||||||
|
|
||||||
DBG(DBG_CONTROL,
|
DBG(DBG_CONTROL,
|
||||||
DBG_log("crl found")
|
DBG_log("crl found")
|
||||||
@@ -435,32 +435,39 @@ cert_status_t verify_by_crl(const x509cert_t *cert, time_t *until,
|
|||||||
lock_authcert_list("verify_by_crl");
|
lock_authcert_list("verify_by_crl");
|
||||||
|
|
||||||
issuer_cert = get_authcert(issuer_dn, authKeyID, X509_CA);
|
issuer_cert = get_authcert(issuer_dn, authKeyID, X509_CA);
|
||||||
valid = cert_crl->issued_by(cert_crl, issuer_cert->cert);
|
trusted = cert_crl->issued_by(cert_crl, issuer_cert->cert);
|
||||||
|
|
||||||
unlock_authcert_list("verify_by_crl");
|
unlock_authcert_list("verify_by_crl");
|
||||||
|
|
||||||
if (valid)
|
if (trusted)
|
||||||
{
|
{
|
||||||
time_t now, nextUpdate;
|
|
||||||
cert_status_t status;
|
cert_status_t status;
|
||||||
|
|
||||||
DBG(DBG_CONTROL,
|
DBG(DBG_CONTROL,
|
||||||
DBG_log("crl signature is valid")
|
DBG_log("crl signature is valid")
|
||||||
)
|
)
|
||||||
/* return the expiration date */
|
|
||||||
time(&now);
|
/* return the expiration date */
|
||||||
cert_crl->get_validity(cert_crl, &now, NULL, &nextUpdate);
|
valid = cert_crl->get_validity(cert_crl, NULL, NULL, until);
|
||||||
*until = nextUpdate;
|
|
||||||
|
|
||||||
/* has the certificate been revoked? */
|
/* has the certificate been revoked? */
|
||||||
status = check_revocation(crl, x509->get_serial(x509), revocationDate
|
status = check_revocation(crl, x509->get_serial(x509), revocationDate
|
||||||
, revocationReason);
|
, revocationReason);
|
||||||
|
|
||||||
if (*until < now)
|
if (valid)
|
||||||
|
{
|
||||||
|
unlock_crl_list("verify_by_crl");
|
||||||
|
DBG(DBG_CONTROL,
|
||||||
|
DBG_log("crl is valid: until %T", until, FALSE)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
else
|
||||||
{
|
{
|
||||||
fetch_req_t *req;
|
fetch_req_t *req;
|
||||||
|
|
||||||
plog("crl update is overdue since %T", until, TRUE);
|
DBG(DBG_CONTROL,
|
||||||
|
DBG_log("crl is stale: since %T", until, FALSE)
|
||||||
|
)
|
||||||
|
|
||||||
/* try to fetch a crl update */
|
/* try to fetch a crl update */
|
||||||
req = build_crl_fetch_request(issuer_dn, authKeyID,
|
req = build_crl_fetch_request(issuer_dn, authKeyID,
|
||||||
@@ -470,13 +477,6 @@ cert_status_t verify_by_crl(const x509cert_t *cert, time_t *until,
|
|||||||
add_crl_fetch_request(req);
|
add_crl_fetch_request(req);
|
||||||
wake_fetch_thread("verify_by_crl");
|
wake_fetch_thread("verify_by_crl");
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
unlock_crl_list("verify_by_crl");
|
|
||||||
DBG(DBG_CONTROL,
|
|
||||||
DBG_log("crl is valid")
|
|
||||||
)
|
|
||||||
}
|
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|||||||
+3
-10
@@ -424,7 +424,7 @@ cert_status_t verify_by_ocsp(const x509cert_t *cert, time_t *until,
|
|||||||
chunk_t serialNumber = x509->get_serial(x509);
|
chunk_t serialNumber = x509->get_serial(x509);
|
||||||
cert_status_t status;
|
cert_status_t status;
|
||||||
ocsp_location_t location;
|
ocsp_location_t location;
|
||||||
time_t nextUpdate = 0;
|
time_t nextUpdate;
|
||||||
|
|
||||||
*revocationDate = UNDEFINED_TIME;
|
*revocationDate = UNDEFINED_TIME;
|
||||||
*revocationReason = CRL_REASON_UNSPECIFIED;
|
*revocationReason = CRL_REASON_UNSPECIFIED;
|
||||||
@@ -1008,9 +1008,6 @@ static bool valid_ocsp_response(response_t *res)
|
|||||||
|
|
||||||
for (pathlen = 0; pathlen < MAX_CA_PATH_LEN; pathlen++)
|
for (pathlen = 0; pathlen < MAX_CA_PATH_LEN; pathlen++)
|
||||||
{
|
{
|
||||||
err_t ugh = NULL;
|
|
||||||
time_t until;
|
|
||||||
|
|
||||||
x509cert_t *cert = authcert;
|
x509cert_t *cert = authcert;
|
||||||
certificate_t *certificate = cert->cert;
|
certificate_t *certificate = cert->cert;
|
||||||
x509_t *x509 = (x509_t*)certificate;
|
x509_t *x509 = (x509_t*)certificate;
|
||||||
@@ -1021,21 +1018,17 @@ static bool valid_ocsp_response(response_t *res)
|
|||||||
DBG(DBG_CONTROL,
|
DBG(DBG_CONTROL,
|
||||||
DBG_log("subject: '%Y'", subject);
|
DBG_log("subject: '%Y'", subject);
|
||||||
DBG_log("issuer: '%Y'", issuer);
|
DBG_log("issuer: '%Y'", issuer);
|
||||||
if (authKeyID.ptr != NULL)
|
if (authKeyID.ptr)
|
||||||
{
|
{
|
||||||
DBG_log("authkey: %#B", &authKeyID);
|
DBG_log("authkey: %#B", &authKeyID);
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
ugh = check_validity(authcert, &until);
|
if (!certificate->get_validity(certificate, NULL, NULL, NULL))
|
||||||
|
|
||||||
if (ugh != NULL)
|
|
||||||
{
|
{
|
||||||
plog("%s", ugh);
|
|
||||||
unlock_authcert_list("valid_ocsp_response");
|
unlock_authcert_list("valid_ocsp_response");
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
DBG(DBG_CONTROL,
|
DBG(DBG_CONTROL,
|
||||||
DBG_log("certificate is valid")
|
DBG_log("certificate is valid")
|
||||||
)
|
)
|
||||||
|
|||||||
+4
-10
@@ -570,21 +570,15 @@ static void scx_find_cert_objects(CK_SLOT_ID slot, CK_SESSION_HANDLE session)
|
|||||||
|
|
||||||
/* check validity of certificate */
|
/* check validity of certificate */
|
||||||
cert = sc->last_cert.u.x509;
|
cert = sc->last_cert.u.x509;
|
||||||
valid_until = cert->notAfter;
|
if (!cert->cert->get_validity(cert->cert, NULL, NULL, &valid_until)
|
||||||
ugh = check_validity(cert, &valid_until);
|
|
||||||
if (ugh != NULL)
|
|
||||||
{
|
{
|
||||||
plog(" %s", ugh);
|
|
||||||
free_x509cert(cert);
|
free_x509cert(cert);
|
||||||
scx_free(sc);
|
scx_free(sc);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
else
|
DBG(DBG_CONTROL,
|
||||||
{
|
DBG_log(" certificate is valid")
|
||||||
DBG(DBG_CONTROL,
|
)
|
||||||
DBG_log(" certificate is valid")
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
sc = scx_add(sc);
|
sc = scx_add(sc);
|
||||||
|
|
||||||
|
|||||||
+12
-42
@@ -1315,41 +1315,6 @@ void parse_authorityKeyIdentifier(chunk_t blob, int level0,
|
|||||||
parser->destroy(parser);
|
parser->destroy(parser);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Verify the validity of a certificate by
|
|
||||||
* checking the notBefore and notAfter dates
|
|
||||||
*/
|
|
||||||
err_t check_validity(const x509cert_t *cert, time_t *until)
|
|
||||||
{
|
|
||||||
time_t current_time, notBefore, notAfter;
|
|
||||||
certificate_t *certificate = cert->cert;
|
|
||||||
|
|
||||||
time(¤t_time);
|
|
||||||
certificate->get_validity(certificate, ¤t_time, ¬Before, ¬After);
|
|
||||||
DBG(DBG_CONTROL | DBG_PARSING ,
|
|
||||||
DBG_log(" not before : %T", ¬Before, TRUE);
|
|
||||||
DBG_log(" current time: %T", ¤t_time, TRUE);
|
|
||||||
DBG_log(" not after : %T", ¬After, TRUE);
|
|
||||||
)
|
|
||||||
|
|
||||||
if (*until == 0 || notAfter < *until)
|
|
||||||
{
|
|
||||||
*until = notAfter;
|
|
||||||
}
|
|
||||||
if (current_time < notBefore)
|
|
||||||
{
|
|
||||||
return "certificate is not valid yet";
|
|
||||||
}
|
|
||||||
if (current_time > notAfter)
|
|
||||||
{
|
|
||||||
return "certificate has expired";
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Verifies a X.509 certificate
|
* Verifies a X.509 certificate
|
||||||
*/
|
*/
|
||||||
@@ -1367,25 +1332,30 @@ bool verify_x509cert(const x509cert_t *cert, bool strict, time_t *until)
|
|||||||
x509_t *x509 = (x509_t*)certificate;
|
x509_t *x509 = (x509_t*)certificate;
|
||||||
chunk_t authKeyID = x509->get_authKeyIdentifier(x509);
|
chunk_t authKeyID = x509->get_authKeyIdentifier(x509);
|
||||||
x509cert_t *issuer_cert;
|
x509cert_t *issuer_cert;
|
||||||
err_t ugh = NULL;
|
time_t notBefore, notAfter;
|
||||||
|
bool valid;
|
||||||
|
|
||||||
DBG(DBG_CONTROL,
|
DBG(DBG_CONTROL,
|
||||||
DBG_log("subject: '%Y'", subject);
|
DBG_log("subject: '%Y'", subject);
|
||||||
DBG_log("issuer: '%Y'", issuer);
|
DBG_log("issuer: '%Y'", issuer);
|
||||||
if (authKeyID.ptr != NULL)
|
if (authKeyID.ptr)
|
||||||
{
|
{
|
||||||
DBG_log("authkey: %#B", &authKeyID);
|
DBG_log("authkey: %#B", &authKeyID);
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
ugh = check_validity(cert, until);
|
valid = certificate->get_validity(certificate, NULL,
|
||||||
|
¬Before, ¬After);
|
||||||
if (ugh != NULL)
|
if (*until == UNDEFINED_TIME || notAfter < *until)
|
||||||
{
|
{
|
||||||
plog("%s", ugh);
|
*until = notAfter;
|
||||||
|
}
|
||||||
|
if (!valid)
|
||||||
|
{
|
||||||
|
plog("certificate is invalid (valid from %T to %T)",
|
||||||
|
¬Before, FALSE, ¬After, FALSE);
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
DBG(DBG_CONTROL,
|
DBG(DBG_CONTROL,
|
||||||
DBG_log("certificate is valid")
|
DBG_log("certificate is valid")
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -77,7 +77,6 @@ extern void parse_authorityKeyIdentifier(chunk_t blob, int level0,
|
|||||||
chunk_t *authKeyID,
|
chunk_t *authKeyID,
|
||||||
chunk_t *authKeySerialNumber);
|
chunk_t *authKeySerialNumber);
|
||||||
extern chunk_t get_directoryName(chunk_t blob, int level, bool implicit);
|
extern chunk_t get_directoryName(chunk_t blob, int level, bool implicit);
|
||||||
extern err_t check_validity(const x509cert_t *cert, time_t *until);
|
|
||||||
extern bool x509_check_signature(chunk_t tbs, chunk_t sig, int algorithm,
|
extern bool x509_check_signature(chunk_t tbs, chunk_t sig, int algorithm,
|
||||||
certificate_t *issuer_cert);
|
certificate_t *issuer_cert);
|
||||||
extern chunk_t x509_build_signature(chunk_t tbs, int algorithm,
|
extern chunk_t x509_build_signature(chunk_t tbs, int algorithm,
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
moon::cat /var/log/auth.log::loaded crl from::YES
|
moon::cat /var/log/auth.log::loaded crl from::YES
|
||||||
carol::cat /var/log/auth.log::loaded crl from::YES
|
carol::cat /var/log/auth.log::loaded crl from::YES
|
||||||
moon::cat /var/log/auth.log::crl update is overdue::YES
|
moon::cat /var/log/auth.log::crl is stale ::YES
|
||||||
carol::cat /var/log/auth.log::crl update is overdue::YES
|
carol::cat /var/log/auth.log::crl is stale::YES
|
||||||
moon::cat /var/log/auth.log::X.509 certificate rejected::YES
|
moon::cat /var/log/auth.log::X.509 certificate rejected::YES
|
||||||
carol::cat /var/log/auth.log::X.509 certificate rejected::YES
|
carol::cat /var/log/auth.log::X.509 certificate rejected::YES
|
||||||
moon::cat /var/log/auth.log::ignoring informational payload, type INVALID_KEY_INFORMATION::YES
|
moon::cat /var/log/auth.log::ignoring informational payload, type INVALID_KEY_INFORMATION::YES
|
||||||
|
|||||||
Reference in New Issue
Block a user