auth/rsa2x509, auth/rsa2csr: allow appending SubjectAlternativeNames (SAN) to multi-domain certificate generation
This commit is contained in:
parent
cb4b187f10
commit
67158d5b05
2 changed files with 123 additions and 8 deletions
|
@ -213,6 +213,10 @@ This info is typically in the form:
|
||||||
C=US ST=NJ L=07974 O=Lucent OU='Bell Labs' CN=G.R.Emlin
|
C=US ST=NJ L=07974 O=Lucent OU='Bell Labs' CN=G.R.Emlin
|
||||||
.EE
|
.EE
|
||||||
.LP
|
.LP
|
||||||
|
One can append further Distinguished Names, DNS Names and
|
||||||
|
E-Mail addresses as a ``Subject Alternative Name'' separated
|
||||||
|
with a comma after the main subject.
|
||||||
|
.LP
|
||||||
The X.509 ASN.1/DER format is often encoded in text using a PEM section
|
The X.509 ASN.1/DER format is often encoded in text using a PEM section
|
||||||
labeled as a
|
labeled as a
|
||||||
.RB `` CERTIFICATE .''
|
.RB `` CERTIFICATE .''
|
||||||
|
|
|
@ -2672,6 +2672,102 @@ asn1encodedigest(DigestState* (*fun)(uchar*, ulong, uchar*, DigestState*), uchar
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static Elem
|
||||||
|
mkaltname(char *s)
|
||||||
|
{
|
||||||
|
Elem e;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for(i=0; i<nelem(DN_oid); i++){
|
||||||
|
if(strstr(s, DN_oid[i].prefix) != nil){
|
||||||
|
e = mkseq(mkel(mkDN(s),nil));
|
||||||
|
e.tag.class = Context;
|
||||||
|
e.tag.num = 4; /* DN */
|
||||||
|
return e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
e = mkstring(s, IA5String);
|
||||||
|
e.tag.class = Context;
|
||||||
|
e.tag.num = strchr(s, '@') != nil ? 1 : 2; /* email : DNS */
|
||||||
|
return e;
|
||||||
|
}
|
||||||
|
|
||||||
|
static Elist*
|
||||||
|
mkaltnames(char *alts)
|
||||||
|
{
|
||||||
|
Elist *el;
|
||||||
|
char *s, *p;
|
||||||
|
|
||||||
|
if(alts == nil)
|
||||||
|
return nil;
|
||||||
|
|
||||||
|
el = nil;
|
||||||
|
alts = estrdup(alts);
|
||||||
|
for(s = alts; s != nil; s = p){
|
||||||
|
while(*s == ' ')
|
||||||
|
s++;
|
||||||
|
if(*s == '\0')
|
||||||
|
break;
|
||||||
|
if((p = strchr(s, ',')) != nil)
|
||||||
|
*p++ = 0;
|
||||||
|
el = mkel(mkaltname(s), el);
|
||||||
|
}
|
||||||
|
free(alts);
|
||||||
|
return el;
|
||||||
|
}
|
||||||
|
|
||||||
|
static Elist*
|
||||||
|
mkextel(Elem e, Ints *oid, Elist *el)
|
||||||
|
{
|
||||||
|
Bytes *b = nil;
|
||||||
|
|
||||||
|
if(encode(e, &b) == ASN_OK){
|
||||||
|
el = mkel(mkseq(
|
||||||
|
mkel(mkoid(oid),
|
||||||
|
mkel(mkoctet(b->data, b->len),
|
||||||
|
nil))), el);
|
||||||
|
freebytes(b);
|
||||||
|
}
|
||||||
|
freevalfields(&e.val);
|
||||||
|
return el;
|
||||||
|
}
|
||||||
|
|
||||||
|
static Ints15 oid_subjectAltName = {4, 2, 5, 29, 17 };
|
||||||
|
|
||||||
|
static Elist*
|
||||||
|
mkextensions(char *alts)
|
||||||
|
{
|
||||||
|
Elist *sl, *xl;
|
||||||
|
Elem e;
|
||||||
|
|
||||||
|
xl = nil;
|
||||||
|
if((sl = mkaltnames(alts)) != nil)
|
||||||
|
xl = mkextel(mkseq(sl), (Ints*)&oid_subjectAltName, xl);
|
||||||
|
if(xl != nil){
|
||||||
|
e = mkseq(mkel(mkseq(xl), nil));
|
||||||
|
e.tag.class = Context;
|
||||||
|
e.tag.num = 3; /* Extensions */
|
||||||
|
return mkel(e, nil);
|
||||||
|
}
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
static char*
|
||||||
|
splitalts(char *s)
|
||||||
|
{
|
||||||
|
int q;
|
||||||
|
|
||||||
|
for(q = 0; *s != '\0'; s++){
|
||||||
|
if(*s == '\'')
|
||||||
|
q ^= 1;
|
||||||
|
else if(q == 0 && *s == ','){
|
||||||
|
*s++ = 0;
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
|
||||||
uchar*
|
uchar*
|
||||||
X509rsagen(RSApriv *priv, char *subj, ulong valid[2], int *certlen)
|
X509rsagen(RSApriv *priv, char *subj, ulong valid[2], int *certlen)
|
||||||
{
|
{
|
||||||
|
@ -2684,11 +2780,16 @@ X509rsagen(RSApriv *priv, char *subj, ulong valid[2], int *certlen)
|
||||||
uchar digest[MAXdlen], *buf;
|
uchar digest[MAXdlen], *buf;
|
||||||
int buflen;
|
int buflen;
|
||||||
mpint *pkcs1;
|
mpint *pkcs1;
|
||||||
|
char *alts;
|
||||||
|
|
||||||
|
subj = estrdup(subj);
|
||||||
|
alts = splitalts(subj);
|
||||||
|
|
||||||
e = mkseq(mkel(mkbigint(pk->n),mkel(mkint(mptoi(pk->ek)),nil)));
|
e = mkseq(mkel(mkbigint(pk->n),mkel(mkint(mptoi(pk->ek)),nil)));
|
||||||
if(encode(e, &pkbytes) != ASN_OK)
|
if(encode(e, &pkbytes) != ASN_OK)
|
||||||
goto errret;
|
goto errret;
|
||||||
freevalfields(&e.val);
|
freevalfields(&e.val);
|
||||||
|
|
||||||
e = mkseq(
|
e = mkseq(
|
||||||
mkel(mkint(serial),
|
mkel(mkint(serial),
|
||||||
mkel(mkalg(sigalg),
|
mkel(mkalg(sigalg),
|
||||||
|
@ -2702,7 +2803,7 @@ X509rsagen(RSApriv *priv, char *subj, ulong valid[2], int *certlen)
|
||||||
mkel(mkalg(ALG_rsaEncryption),
|
mkel(mkalg(ALG_rsaEncryption),
|
||||||
mkel(mkbits(pkbytes->data, pkbytes->len),
|
mkel(mkbits(pkbytes->data, pkbytes->len),
|
||||||
nil))),
|
nil))),
|
||||||
nil)))))));
|
mkextensions(alts))))))));
|
||||||
freebytes(pkbytes);
|
freebytes(pkbytes);
|
||||||
if(encode(e, &certinfobytes) != ASN_OK)
|
if(encode(e, &certinfobytes) != ASN_OK)
|
||||||
goto errret;
|
goto errret;
|
||||||
|
@ -2737,6 +2838,7 @@ X509rsagen(RSApriv *priv, char *subj, ulong valid[2], int *certlen)
|
||||||
freebytes(certbytes);
|
freebytes(certbytes);
|
||||||
errret:
|
errret:
|
||||||
freevalfields(&e.val);
|
freevalfields(&e.val);
|
||||||
|
free(subj);
|
||||||
return cert;
|
return cert;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2753,6 +2855,10 @@ X509rsareq(RSApriv *priv, char *subj, int *certlen)
|
||||||
uchar digest[MAXdlen], *buf;
|
uchar digest[MAXdlen], *buf;
|
||||||
int buflen;
|
int buflen;
|
||||||
mpint *pkcs1;
|
mpint *pkcs1;
|
||||||
|
char *alts;
|
||||||
|
|
||||||
|
subj = estrdup(subj);
|
||||||
|
alts = splitalts(subj);
|
||||||
|
|
||||||
e = mkseq(mkel(mkbigint(pk->n),mkel(mkint(mptoi(pk->ek)),nil)));
|
e = mkseq(mkel(mkbigint(pk->n),mkel(mkint(mptoi(pk->ek)),nil)));
|
||||||
if(encode(e, &pkbytes) != ASN_OK)
|
if(encode(e, &pkbytes) != ASN_OK)
|
||||||
|
@ -2765,7 +2871,7 @@ X509rsareq(RSApriv *priv, char *subj, int *certlen)
|
||||||
mkel(mkalg(ALG_rsaEncryption),
|
mkel(mkalg(ALG_rsaEncryption),
|
||||||
mkel(mkbits(pkbytes->data, pkbytes->len),
|
mkel(mkbits(pkbytes->data, pkbytes->len),
|
||||||
nil))),
|
nil))),
|
||||||
nil))));
|
mkextensions(alts)))));
|
||||||
freebytes(pkbytes);
|
freebytes(pkbytes);
|
||||||
if(encode(e, &certinfobytes) != ASN_OK)
|
if(encode(e, &certinfobytes) != ASN_OK)
|
||||||
goto errret;
|
goto errret;
|
||||||
|
@ -2799,14 +2905,19 @@ X509rsareq(RSApriv *priv, char *subj, int *certlen)
|
||||||
freebytes(certbytes);
|
freebytes(certbytes);
|
||||||
errret:
|
errret:
|
||||||
freevalfields(&e.val);
|
freevalfields(&e.val);
|
||||||
|
free(subj);
|
||||||
return cert;
|
return cert;
|
||||||
}
|
}
|
||||||
|
|
||||||
static char*
|
static char*
|
||||||
tagdump(Tag tag)
|
tagdump(Tag tag)
|
||||||
{
|
{
|
||||||
if(tag.class != Universal)
|
static char buf[32];
|
||||||
return smprint("class%d,num%d", tag.class, tag.num);
|
|
||||||
|
if(tag.class != Universal){
|
||||||
|
snprint(buf, sizeof(buf), "class%d,num%d", tag.class, tag.num);
|
||||||
|
return buf;
|
||||||
|
}
|
||||||
switch(tag.num){
|
switch(tag.num){
|
||||||
case BOOLEAN: return "BOOLEAN";
|
case BOOLEAN: return "BOOLEAN";
|
||||||
case INTEGER: return "INTEGER";
|
case INTEGER: return "INTEGER";
|
||||||
|
@ -2835,7 +2946,8 @@ tagdump(Tag tag)
|
||||||
case UniversalString: return "UniversalString";
|
case UniversalString: return "UniversalString";
|
||||||
case BMPString: return "BMPString";
|
case BMPString: return "BMPString";
|
||||||
default:
|
default:
|
||||||
return smprint("Universal,num%d", tag.num);
|
snprint(buf, sizeof(buf), "Universal,num%d", tag.num);
|
||||||
|
return buf;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2855,7 +2967,7 @@ edump(Elem e)
|
||||||
case VBigInt: print("BigInt[%d] %.2x%.2x...",v.u.bigintval->len,v.u.bigintval->data[0],v.u.bigintval->data[1]); break;
|
case VBigInt: print("BigInt[%d] %.2x%.2x...",v.u.bigintval->len,v.u.bigintval->data[0],v.u.bigintval->data[1]); break;
|
||||||
case VReal: print("Real..."); break;
|
case VReal: print("Real..."); break;
|
||||||
case VOther: print("Other..."); break;
|
case VOther: print("Other..."); break;
|
||||||
case VBitString: print("BitString..."); break;
|
case VBitString: print("BitString[%d]...", v.u.bitstringval->len*8 - v.u.bitstringval->unusedbits); break;
|
||||||
case VNull: print("Null"); break;
|
case VNull: print("Null"); break;
|
||||||
case VEOC: print("EOC..."); break;
|
case VEOC: print("EOC..."); break;
|
||||||
case VObjId: print("ObjId");
|
case VObjId: print("ObjId");
|
||||||
|
@ -2919,7 +3031,6 @@ X509dump(uchar *cert, int ncert)
|
||||||
print("issuer %s\n", c->issuer);
|
print("issuer %s\n", c->issuer);
|
||||||
print("validity %s %s\n", c->validity_start, c->validity_end);
|
print("validity %s %s\n", c->validity_start, c->validity_end);
|
||||||
print("subject %s\n", c->subject);
|
print("subject %s\n", c->subject);
|
||||||
|
|
||||||
print("sigalg=%d digest=%.*H\n", c->signature_alg, digestlen, digest);
|
print("sigalg=%d digest=%.*H\n", c->signature_alg, digestlen, digest);
|
||||||
print("publickey_alg=%d pubkey[%d] %.*H\n", c->publickey_alg, c->publickey->len,
|
print("publickey_alg=%d pubkey[%d] %.*H\n", c->publickey_alg, c->publickey->len,
|
||||||
c->publickey->len, c->publickey->data);
|
c->publickey->len, c->publickey->data);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue