Add support for public key input and output in rsa and dsa utilities with some
new DSA public key functions that were missing. Also beginning of a cache for X509_EXTENSION structures: this will allow them to be accessed more quickly for things like certificate chain verification...
This commit is contained in:
parent
393f2c651d
commit
3ea23631d4
6
CHANGES
6
CHANGES
@ -4,6 +4,12 @@
|
|||||||
|
|
||||||
Changes between 0.9.4 and 0.9.5 [xx XXX 1999]
|
Changes between 0.9.4 and 0.9.5 [xx XXX 1999]
|
||||||
|
|
||||||
|
*) Add -pubin and -pubout options to the rsa and dsa commands. These allow
|
||||||
|
a public key to be input or output. For example:
|
||||||
|
openssl rsa -in key.pem -pubout -out pubkey.pem
|
||||||
|
Also added necessary DSA public key functions to handle this.
|
||||||
|
[Steve Henson]
|
||||||
|
|
||||||
*) Fix so PKCS7_dataVerify() doesn't crash if no certificates are contained
|
*) Fix so PKCS7_dataVerify() doesn't crash if no certificates are contained
|
||||||
in the message. This was handled by allowing
|
in the message. This was handled by allowing
|
||||||
X509_find_by_issuer_and_serial() to tolerate a NULL passed to it.
|
X509_find_by_issuer_and_serial() to tolerate a NULL passed to it.
|
||||||
|
36
apps/dsa.c
36
apps/dsa.c
@ -91,6 +91,7 @@ int MAIN(int argc, char **argv)
|
|||||||
const EVP_CIPHER *enc=NULL;
|
const EVP_CIPHER *enc=NULL;
|
||||||
BIO *in=NULL,*out=NULL;
|
BIO *in=NULL,*out=NULL;
|
||||||
int informat,outformat,text=0,noout=0;
|
int informat,outformat,text=0,noout=0;
|
||||||
|
int pubin = 0, pubout = 0;
|
||||||
char *infile,*outfile,*prog;
|
char *infile,*outfile,*prog;
|
||||||
int modulus=0;
|
int modulus=0;
|
||||||
|
|
||||||
@ -136,6 +137,10 @@ int MAIN(int argc, char **argv)
|
|||||||
text=1;
|
text=1;
|
||||||
else if (strcmp(*argv,"-modulus") == 0)
|
else if (strcmp(*argv,"-modulus") == 0)
|
||||||
modulus=1;
|
modulus=1;
|
||||||
|
else if (strcmp(*argv,"-pubin") == 0)
|
||||||
|
pubin=1;
|
||||||
|
else if (strcmp(*argv,"-pubout") == 0)
|
||||||
|
pubout=1;
|
||||||
else if ((enc=EVP_get_cipherbyname(&(argv[0][1]))) == NULL)
|
else if ((enc=EVP_get_cipherbyname(&(argv[0][1]))) == NULL)
|
||||||
{
|
{
|
||||||
BIO_printf(bio_err,"unknown option %s\n",*argv);
|
BIO_printf(bio_err,"unknown option %s\n",*argv);
|
||||||
@ -187,19 +192,21 @@ bad:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
BIO_printf(bio_err,"read DSA private key\n");
|
BIO_printf(bio_err,"read DSA key\n");
|
||||||
if (informat == FORMAT_ASN1)
|
if (informat == FORMAT_ASN1) {
|
||||||
dsa=d2i_DSAPrivateKey_bio(in,NULL);
|
if(pubin) dsa=d2i_DSAPublicKey_bio(in,NULL);
|
||||||
else if (informat == FORMAT_PEM)
|
else dsa=d2i_DSAPrivateKey_bio(in,NULL);
|
||||||
dsa=PEM_read_bio_DSAPrivateKey(in,NULL,NULL,NULL);
|
} else if (informat == FORMAT_PEM) {
|
||||||
else
|
if(pubin) dsa=PEM_read_bio_DSAPublicKey(in,NULL, NULL, NULL);
|
||||||
|
else dsa=PEM_read_bio_DSAPrivateKey(in,NULL,NULL,NULL);
|
||||||
|
} else
|
||||||
{
|
{
|
||||||
BIO_printf(bio_err,"bad input format specified for key\n");
|
BIO_printf(bio_err,"bad input format specified for key\n");
|
||||||
goto end;
|
goto end;
|
||||||
}
|
}
|
||||||
if (dsa == NULL)
|
if (dsa == NULL)
|
||||||
{
|
{
|
||||||
BIO_printf(bio_err,"unable to load Private Key\n");
|
BIO_printf(bio_err,"unable to load Key\n");
|
||||||
ERR_print_errors(bio_err);
|
ERR_print_errors(bio_err);
|
||||||
goto end;
|
goto end;
|
||||||
}
|
}
|
||||||
@ -231,12 +238,15 @@ bad:
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (noout) goto end;
|
if (noout) goto end;
|
||||||
BIO_printf(bio_err,"writing DSA private key\n");
|
BIO_printf(bio_err,"writing DSA key\n");
|
||||||
if (outformat == FORMAT_ASN1)
|
if (outformat == FORMAT_ASN1) {
|
||||||
i=i2d_DSAPrivateKey_bio(out,dsa);
|
if(pubin || pubout) i=i2d_DSAPublicKey_bio(out,dsa);
|
||||||
else if (outformat == FORMAT_PEM)
|
else i=i2d_DSAPrivateKey_bio(out,dsa);
|
||||||
i=PEM_write_bio_DSAPrivateKey(out,dsa,enc,NULL,0,NULL,NULL);
|
} else if (outformat == FORMAT_PEM) {
|
||||||
else {
|
if(pubin || pubout)
|
||||||
|
i=PEM_write_bio_DSAPublicKey(out,dsa);
|
||||||
|
else i=PEM_write_bio_DSAPrivateKey(out,dsa,enc,NULL,0,NULL,NULL);
|
||||||
|
} else {
|
||||||
BIO_printf(bio_err,"bad output format specified for outfile\n");
|
BIO_printf(bio_err,"bad output format specified for outfile\n");
|
||||||
goto end;
|
goto end;
|
||||||
}
|
}
|
||||||
|
42
apps/rsa.c
42
apps/rsa.c
@ -82,6 +82,8 @@
|
|||||||
* -text - print a text version
|
* -text - print a text version
|
||||||
* -modulus - print the RSA key modulus
|
* -modulus - print the RSA key modulus
|
||||||
* -check - verify key consistency
|
* -check - verify key consistency
|
||||||
|
* -pubin - Expect a public key in input file.
|
||||||
|
* -pubout - Output a public key.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
int MAIN(int argc, char **argv)
|
int MAIN(int argc, char **argv)
|
||||||
@ -92,6 +94,7 @@ int MAIN(int argc, char **argv)
|
|||||||
const EVP_CIPHER *enc=NULL;
|
const EVP_CIPHER *enc=NULL;
|
||||||
BIO *in=NULL,*out=NULL;
|
BIO *in=NULL,*out=NULL;
|
||||||
int informat,outformat,text=0,check=0,noout=0;
|
int informat,outformat,text=0,check=0,noout=0;
|
||||||
|
int pubin = 0, pubout = 0;
|
||||||
char *infile,*outfile,*prog;
|
char *infile,*outfile,*prog;
|
||||||
int modulus=0;
|
int modulus=0;
|
||||||
|
|
||||||
@ -131,6 +134,10 @@ int MAIN(int argc, char **argv)
|
|||||||
if (--argc < 1) goto bad;
|
if (--argc < 1) goto bad;
|
||||||
outfile= *(++argv);
|
outfile= *(++argv);
|
||||||
}
|
}
|
||||||
|
else if (strcmp(*argv,"-pubin") == 0)
|
||||||
|
pubin=1;
|
||||||
|
else if (strcmp(*argv,"-pubout") == 0)
|
||||||
|
pubout=1;
|
||||||
else if (strcmp(*argv,"-noout") == 0)
|
else if (strcmp(*argv,"-noout") == 0)
|
||||||
noout=1;
|
noout=1;
|
||||||
else if (strcmp(*argv,"-text") == 0)
|
else if (strcmp(*argv,"-text") == 0)
|
||||||
@ -167,6 +174,8 @@ bad:
|
|||||||
BIO_printf(bio_err," -noout don't print key out\n");
|
BIO_printf(bio_err," -noout don't print key out\n");
|
||||||
BIO_printf(bio_err," -modulus print the RSA key modulus\n");
|
BIO_printf(bio_err," -modulus print the RSA key modulus\n");
|
||||||
BIO_printf(bio_err," -check verify key consistency\n");
|
BIO_printf(bio_err," -check verify key consistency\n");
|
||||||
|
BIO_printf(bio_err," -pubin expect a public key in input file\n");
|
||||||
|
BIO_printf(bio_err," -pubout output a public key\n");
|
||||||
goto end;
|
goto end;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -192,8 +201,10 @@ bad:
|
|||||||
}
|
}
|
||||||
|
|
||||||
BIO_printf(bio_err,"read RSA private key\n");
|
BIO_printf(bio_err,"read RSA private key\n");
|
||||||
if (informat == FORMAT_ASN1)
|
if (informat == FORMAT_ASN1) {
|
||||||
rsa=d2i_RSAPrivateKey_bio(in,NULL);
|
if (pubin) rsa=d2i_RSAPublicKey_bio(in,NULL);
|
||||||
|
else rsa=d2i_RSAPrivateKey_bio(in,NULL);
|
||||||
|
}
|
||||||
#ifndef NO_RC4
|
#ifndef NO_RC4
|
||||||
else if (informat == FORMAT_NETSCAPE)
|
else if (informat == FORMAT_NETSCAPE)
|
||||||
{
|
{
|
||||||
@ -221,8 +232,10 @@ bad:
|
|||||||
BUF_MEM_free(buf);
|
BUF_MEM_free(buf);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
else if (informat == FORMAT_PEM)
|
else if (informat == FORMAT_PEM) {
|
||||||
rsa=PEM_read_bio_RSAPrivateKey(in,NULL,NULL,NULL);
|
if(pubin) rsa=PEM_read_bio_RSAPublicKey(in,NULL,NULL,NULL);
|
||||||
|
else rsa=PEM_read_bio_RSAPrivateKey(in,NULL,NULL,NULL);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
BIO_printf(bio_err,"bad input format specified for key\n");
|
BIO_printf(bio_err,"bad input format specified for key\n");
|
||||||
@ -230,7 +243,7 @@ bad:
|
|||||||
}
|
}
|
||||||
if (rsa == NULL)
|
if (rsa == NULL)
|
||||||
{
|
{
|
||||||
BIO_printf(bio_err,"unable to load Private Key\n");
|
BIO_printf(bio_err,"unable to load Key\n");
|
||||||
ERR_print_errors(bio_err);
|
ERR_print_errors(bio_err);
|
||||||
goto end;
|
goto end;
|
||||||
}
|
}
|
||||||
@ -293,9 +306,11 @@ bad:
|
|||||||
ret = 0;
|
ret = 0;
|
||||||
goto end;
|
goto end;
|
||||||
}
|
}
|
||||||
BIO_printf(bio_err,"writing RSA private key\n");
|
BIO_printf(bio_err,"writing RSA key\n");
|
||||||
if (outformat == FORMAT_ASN1)
|
if (outformat == FORMAT_ASN1) {
|
||||||
i=i2d_RSAPrivateKey_bio(out,rsa);
|
if(pubout || pubin) i=i2d_RSAPublicKey_bio(out,rsa);
|
||||||
|
else i=i2d_RSAPrivateKey_bio(out,rsa);
|
||||||
|
}
|
||||||
#ifndef NO_RC4
|
#ifndef NO_RC4
|
||||||
else if (outformat == FORMAT_NETSCAPE)
|
else if (outformat == FORMAT_NETSCAPE)
|
||||||
{
|
{
|
||||||
@ -315,15 +330,18 @@ bad:
|
|||||||
Free(pp);
|
Free(pp);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
else if (outformat == FORMAT_PEM)
|
else if (outformat == FORMAT_PEM) {
|
||||||
i=PEM_write_bio_RSAPrivateKey(out,rsa,enc,NULL,0,NULL,NULL);
|
if(pubout || pubin)
|
||||||
else {
|
i=PEM_write_bio_RSAPublicKey(out,rsa);
|
||||||
|
else
|
||||||
|
i=PEM_write_bio_RSAPrivateKey(out,rsa,enc,NULL,0,NULL,NULL);
|
||||||
|
} else {
|
||||||
BIO_printf(bio_err,"bad output format specified for outfile\n");
|
BIO_printf(bio_err,"bad output format specified for outfile\n");
|
||||||
goto end;
|
goto end;
|
||||||
}
|
}
|
||||||
if (!i)
|
if (!i)
|
||||||
{
|
{
|
||||||
BIO_printf(bio_err,"unable to write private key\n");
|
BIO_printf(bio_err,"unable to write key\n");
|
||||||
ERR_print_errors(bio_err);
|
ERR_print_errors(bio_err);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -100,10 +100,6 @@ X509_EXTENSION *d2i_X509_EXTENSION(X509_EXTENSION **a, unsigned char **pp,
|
|||||||
M_ASN1_D2I_start_sequence();
|
M_ASN1_D2I_start_sequence();
|
||||||
M_ASN1_D2I_get(ret->object,d2i_ASN1_OBJECT);
|
M_ASN1_D2I_get(ret->object,d2i_ASN1_OBJECT);
|
||||||
|
|
||||||
if ((ret->argp != NULL) && (ret->ex_free != NULL))
|
|
||||||
ret->ex_free(ret);
|
|
||||||
ret->argl=0;
|
|
||||||
ret->argp=NULL;
|
|
||||||
ret->netscape_hack=0;
|
ret->netscape_hack=0;
|
||||||
if ((c.slen != 0) &&
|
if ((c.slen != 0) &&
|
||||||
(M_ASN1_next == (V_ASN1_UNIVERSAL|V_ASN1_BOOLEAN)))
|
(M_ASN1_next == (V_ASN1_UNIVERSAL|V_ASN1_BOOLEAN)))
|
||||||
@ -129,9 +125,6 @@ X509_EXTENSION *X509_EXTENSION_new(void)
|
|||||||
M_ASN1_New(ret->value,ASN1_OCTET_STRING_new);
|
M_ASN1_New(ret->value,ASN1_OCTET_STRING_new);
|
||||||
ret->critical=0;
|
ret->critical=0;
|
||||||
ret->netscape_hack=0;
|
ret->netscape_hack=0;
|
||||||
ret->argl=0L;
|
|
||||||
ret->argp=NULL;
|
|
||||||
ret->ex_free=NULL;
|
|
||||||
return(ret);
|
return(ret);
|
||||||
M_ASN1_New_Error(ASN1_F_X509_EXTENSION_NEW);
|
M_ASN1_New_Error(ASN1_F_X509_EXTENSION_NEW);
|
||||||
}
|
}
|
||||||
@ -139,8 +132,6 @@ X509_EXTENSION *X509_EXTENSION_new(void)
|
|||||||
void X509_EXTENSION_free(X509_EXTENSION *a)
|
void X509_EXTENSION_free(X509_EXTENSION *a)
|
||||||
{
|
{
|
||||||
if (a == NULL) return;
|
if (a == NULL) return;
|
||||||
if ((a->argp != NULL) && (a->ex_free != NULL))
|
|
||||||
a->ex_free(a);
|
|
||||||
ASN1_OBJECT_free(a->object);
|
ASN1_OBJECT_free(a->object);
|
||||||
ASN1_OCTET_STRING_free(a->value);
|
ASN1_OCTET_STRING_free(a->value);
|
||||||
Free((char *)a);
|
Free((char *)a);
|
||||||
|
@ -110,6 +110,7 @@ extern "C" {
|
|||||||
#define PEM_STRING_RSA "RSA PRIVATE KEY"
|
#define PEM_STRING_RSA "RSA PRIVATE KEY"
|
||||||
#define PEM_STRING_RSA_PUBLIC "RSA PUBLIC KEY"
|
#define PEM_STRING_RSA_PUBLIC "RSA PUBLIC KEY"
|
||||||
#define PEM_STRING_DSA "DSA PRIVATE KEY"
|
#define PEM_STRING_DSA "DSA PRIVATE KEY"
|
||||||
|
#define PEM_STRING_DSA_PUBLIC "DSA PUBLIC KEY"
|
||||||
#define PEM_STRING_PKCS7 "PKCS7"
|
#define PEM_STRING_PKCS7 "PKCS7"
|
||||||
#define PEM_STRING_PKCS8 "ENCRYPTED PRIVATE KEY"
|
#define PEM_STRING_PKCS8 "ENCRYPTED PRIVATE KEY"
|
||||||
#define PEM_STRING_PKCS8INF "PRIVATE KEY"
|
#define PEM_STRING_PKCS8INF "PRIVATE KEY"
|
||||||
@ -552,6 +553,8 @@ DECLARE_PEM_rw(RSAPublicKey, RSA)
|
|||||||
|
|
||||||
DECLARE_PEM_rw_cb(DSAPrivateKey, DSA)
|
DECLARE_PEM_rw_cb(DSAPrivateKey, DSA)
|
||||||
|
|
||||||
|
DECLARE_PEM_rw(DSAPublicKey, DSA)
|
||||||
|
|
||||||
DECLARE_PEM_rw(DSAparams, DSA)
|
DECLARE_PEM_rw(DSAparams, DSA)
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -92,6 +92,8 @@ IMPLEMENT_PEM_rw(RSAPublicKey, RSA, PEM_STRING_RSA_PUBLIC, RSAPublicKey)
|
|||||||
|
|
||||||
IMPLEMENT_PEM_rw_cb(DSAPrivateKey, DSA, PEM_STRING_DSA, DSAPrivateKey)
|
IMPLEMENT_PEM_rw_cb(DSAPrivateKey, DSA, PEM_STRING_DSA, DSAPrivateKey)
|
||||||
|
|
||||||
|
IMPLEMENT_PEM_rw(DSAPublicKey, DSA, PEM_STRING_DSA_PUBLIC, DSAPublicKey)
|
||||||
|
|
||||||
IMPLEMENT_PEM_rw(DSAparams, DSA, PEM_STRING_DSAPARAMS, DSAparams)
|
IMPLEMENT_PEM_rw(DSAparams, DSA, PEM_STRING_DSAPARAMS, DSAparams)
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -176,9 +176,8 @@ typedef struct X509_extension_st
|
|||||||
short critical;
|
short critical;
|
||||||
short netscape_hack;
|
short netscape_hack;
|
||||||
ASN1_OCTET_STRING *value;
|
ASN1_OCTET_STRING *value;
|
||||||
long argl; /* used when decoding */
|
struct v3_ext_method *method; /* V3 method to use */
|
||||||
char *argp; /* used when decoding */
|
void *ext_val; /* extension value */
|
||||||
void (*ex_free)(); /* clear argp stuff */
|
|
||||||
} X509_EXTENSION;
|
} X509_EXTENSION;
|
||||||
|
|
||||||
DECLARE_STACK_OF(X509_EXTENSION)
|
DECLARE_STACK_OF(X509_EXTENSION)
|
||||||
@ -583,6 +582,8 @@ RSA *d2i_RSAPublicKey_fp(FILE *fp,RSA **rsa);
|
|||||||
int i2d_RSAPublicKey_fp(FILE *fp,RSA *rsa);
|
int i2d_RSAPublicKey_fp(FILE *fp,RSA *rsa);
|
||||||
#endif
|
#endif
|
||||||
#ifndef NO_DSA
|
#ifndef NO_DSA
|
||||||
|
DSA *d2i_DSAPublicKey_fp(FILE *fp, DSA **dsa);
|
||||||
|
int i2d_DSAPublicKey_fp(FILE *fp, DSA *dsa);
|
||||||
DSA *d2i_DSAPrivateKey_fp(FILE *fp, DSA **dsa);
|
DSA *d2i_DSAPrivateKey_fp(FILE *fp, DSA **dsa);
|
||||||
int i2d_DSAPrivateKey_fp(FILE *fp, DSA *dsa);
|
int i2d_DSAPrivateKey_fp(FILE *fp, DSA *dsa);
|
||||||
X509_SIG *d2i_PKCS8_fp(FILE *fp,X509_SIG **p8);
|
X509_SIG *d2i_PKCS8_fp(FILE *fp,X509_SIG **p8);
|
||||||
@ -607,6 +608,8 @@ RSA *d2i_RSAPublicKey_bio(BIO *bp,RSA **rsa);
|
|||||||
int i2d_RSAPublicKey_bio(BIO *bp,RSA *rsa);
|
int i2d_RSAPublicKey_bio(BIO *bp,RSA *rsa);
|
||||||
#endif
|
#endif
|
||||||
#ifndef NO_DSA
|
#ifndef NO_DSA
|
||||||
|
DSA *d2i_DSAPublicKey_bio(BIO *bp, DSA **dsa);
|
||||||
|
int i2d_DSAPublicKey_bio(BIO *bp, DSA *dsa);
|
||||||
DSA *d2i_DSAPrivateKey_bio(BIO *bp, DSA **dsa);
|
DSA *d2i_DSAPrivateKey_bio(BIO *bp, DSA **dsa);
|
||||||
int i2d_DSAPrivateKey_bio(BIO *bp, DSA *dsa);
|
int i2d_DSAPrivateKey_bio(BIO *bp, DSA *dsa);
|
||||||
#endif
|
#endif
|
||||||
|
@ -329,6 +329,18 @@ int i2d_DSAPrivateKey_fp(FILE *fp, DSA *dsa)
|
|||||||
{
|
{
|
||||||
return(ASN1_i2d_fp(i2d_DSAPrivateKey,fp,(unsigned char *)dsa));
|
return(ASN1_i2d_fp(i2d_DSAPrivateKey,fp,(unsigned char *)dsa));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DSA *d2i_DSAPublicKey_fp(FILE *fp, DSA **dsa)
|
||||||
|
{
|
||||||
|
return((DSA *)ASN1_d2i_fp((char *(*)())
|
||||||
|
DSA_new,(char *(*)())d2i_DSAPublicKey, (fp),
|
||||||
|
(unsigned char **)(dsa)));
|
||||||
|
}
|
||||||
|
|
||||||
|
int i2d_DSAPublicKey_fp(FILE *fp, DSA *dsa)
|
||||||
|
{
|
||||||
|
return(ASN1_i2d_fp(i2d_DSAPublicKey,fp,(unsigned char *)dsa));
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
DSA *d2i_DSAPrivateKey_bio(BIO *bp, DSA **dsa)
|
DSA *d2i_DSAPrivateKey_bio(BIO *bp, DSA **dsa)
|
||||||
@ -342,6 +354,19 @@ int i2d_DSAPrivateKey_bio(BIO *bp, DSA *dsa)
|
|||||||
{
|
{
|
||||||
return(ASN1_i2d_bio(i2d_DSAPrivateKey,bp,(unsigned char *)dsa));
|
return(ASN1_i2d_bio(i2d_DSAPrivateKey,bp,(unsigned char *)dsa));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DSA *d2i_DSAPublicKey_bio(BIO *bp, DSA **dsa)
|
||||||
|
{
|
||||||
|
return((DSA *)ASN1_d2i_bio((char *(*)())
|
||||||
|
DSA_new,(char *(*)())d2i_DSAPublicKey, (bp),
|
||||||
|
(unsigned char **)(dsa)));
|
||||||
|
}
|
||||||
|
|
||||||
|
int i2d_DSAPublicKey_bio(BIO *bp, DSA *dsa)
|
||||||
|
{
|
||||||
|
return(ASN1_i2d_bio(i2d_DSAPublicKey,bp,(unsigned char *)dsa));
|
||||||
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
X509_ALGOR *X509_ALGOR_dup(X509_ALGOR *xn)
|
X509_ALGOR *X509_ALGOR_dup(X509_ALGOR *xn)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user