implement X509; include "sys.m"; sys : Sys; include "asn1.m"; asn1 : ASN1; Elem, Tag, Value, Oid, Universal, Context, BOOLEAN, INTEGER, BIT_STRING, OCTET_STRING, OBJECT_ID, SEQUENCE, UTCTime, IA5String, GeneralString, GeneralizedTime : import asn1; include "keyring.m"; keyring : Keyring; IPint, DESstate : import keyring; include "security.m"; random : Random; include "daytime.m"; daytime : Daytime; include "pkcs.m"; pkcs : PKCS; include "x509.m"; X509_DEBUG : con 0;logfd : ref Sys->FD; TAG_MASK : con 16r1F;CONSTR_MASK : con 16r20;CLASS_MASK : con 16rC0; # object identifiers objIdTab = array [] of { id_at => Oid(array [] of {2,5,4}), id_at_commonName => Oid(array [] of {2,5,4,3}), id_at_countryName => Oid(array [] of {2,5,4,6}), id_at_localityName => Oid(array [] of {2,5,4,7}), id_at_stateOrProvinceName => Oid(array [] of {2,5,4,8}), id_at_organizationName => Oid(array [] of {2,5,4,10}), id_at_organizationalUnitName => Oid(array [] of {2,5,4,11}), id_at_userPassword => Oid(array [] of {2,5,4,35}), id_at_userCertificate => Oid(array [] of {2,5,4,36}), id_at_cAcertificate => Oid(array [] of {2,5,4,37}), id_at_authorityRevocationList => Oid(array [] of {2,5,4,38}), id_at_certificateRevocationList => Oid(array [] of {2,5,4,39}), id_at_crossCertificatePair => Oid(array [] of {2,5,4,40}),# id_at_crossCertificatePair => Oid(array [] of {2,5,4,58}), id_at_supportedAlgorithms => Oid(array [] of {2,5,4,52}), id_at_deltaRevocationList => Oid(array [] of {2,5,4,53}), id_ce => Oid(array [] of {2,5,29}), id_ce_subjectDirectoryAttributes => Oid(array [] of {2,5,29,9}), id_ce_subjectKeyIdentifier => Oid(array [] of {2,5,29,14}), id_ce_keyUsage => Oid(array [] of {2,5,29,15}), id_ce_privateKeyUsage => Oid(array [] of {2,5,29,16}), id_ce_subjectAltName => Oid(array [] of {2,5,29,17}), id_ce_issuerAltName => Oid(array [] of {2,5,29,18}), id_ce_basicConstraints => Oid(array [] of {2,5,29,19}), id_ce_cRLNumber => Oid(array [] of {2,5,29,20}), id_ce_reasonCode => Oid(array [] of {2,5,29,21}), id_ce_instructionCode => Oid(array [] of {2,5,29,23}), id_ce_invalidityDate => Oid(array [] of {2,5,29,24}), id_ce_deltaCRLIndicator => Oid(array [] of {2,5,29,27}), id_ce_issuingDistributionPoint => Oid(array [] of {2,5,29,28}), id_ce_certificateIssuer => Oid(array [] of {2,5,29,29}), id_ce_nameConstraints => Oid(array [] of {2,5,29,30}), id_ce_cRLDistributionPoint => Oid(array [] of {2,5,29,31}), id_ce_certificatePolicies => Oid(array [] of {2,5,29,32}), id_ce_policyMapping => Oid(array [] of {2,5,29,33}), id_ce_authorityKeyIdentifier => Oid(array [] of {2,5,29,35}), id_ce_policyConstraints => Oid(array [] of {2,5,29,36}), # id_mr => Oid(array [] of {2,5,?}),# id_mr_certificateMatch => Oid(array [] of {2,5,?,35}),# id_mr_certificatePairExactMatch =># Oid(array [] of {2,5,?,36}),# id_mr_certificatePairMatch => Oid(array [] of {2,5,?,37}),# id_mr_certificateListExactMatch =># Oid(array [] of {2,5,?,38}),# id_mr_certificateListMatch => Oid(array [] of {2,5,?,39}),# id_mr_algorithmidentifierMatch =># Oid(array [] of {2,5,?,40})}; # [public] init(): string{ sys = load Sys Sys->PATH; if(X509_DEBUG) logfd = sys->fildes(1); keyring = load Keyring Keyring->PATH; if(keyring == nil) return sys->sprint("load %s: %r", Keyring->PATH); random = load Random Random->PATH; if(random == nil) return sys->sprint("load %s: %r", Random->PATH); daytime = load Daytime Daytime->PATH; if(daytime == nil) return sys->sprint("load %s: %r", Daytime->PATH); asn1 = load ASN1 ASN1->PATH; if(asn1 == nil) return sys->sprint("load %s: %r", ASN1->PATH); asn1->init(); pkcs = load PKCS PKCS->PATH; if(pkcs == nil) return sys->sprint("load %s: %r", PKCS->PATH); if((e := pkcs->init()) != nil) return sys->sprint("pkcs: %s", e); return nil;} # [private] log(s: string){ if(X509_DEBUG) sys->fprint(logfd, "x509: %s\n", s);} ## SIGNED { ToBeSigned } ::= SEQUENCE {## toBeSigned ToBeSigned,## COMPONENTS OF SIGNATURE { ToBeSigned }}#### SIGNATURE {OfSignature} ::= SEQUENCE {## algorithmIdentifier AlgorithmIdentifier,## encrypted ENCRYPTED { HASHED { OfSignature }}}#### ENCRYPTED { ToBeEnciphered } ::= BIT STRING ( CONSTRAINED BY {## -- must be the result of applying an encipherment procedure --## -- to the BER-encoded octets of a value of -- ToBeEnciphered } ) # [public] Signed.decode(a: array of byte): (string, ref Signed){parse: for(;;) { # interpret the enclosing structure (ok, tag, i, n) := der_dec1(a, 0, len a); if(!ok || n != len a || !tag.constr || tag.class != Universal || tag.num != SEQUENCE) break parse; s := ref Signed; # SIGNED sequence istart := i; (ok, tag, i, n) = der_dec1(a, i, len a); if(!ok || n == len a) break parse; s.tobe_signed = a[istart:n]; # AlgIdentifier istart = n; (ok, tag, i, n) = der_dec1(a, n, len a); if(!ok || n == len a || !tag.constr || tag.class != Universal || tag.num != SEQUENCE) { if(X509_DEBUG) log("signed: der data: " + sys->sprint("ok=%d, n=%d, constr=%d, class=%d, num=%d", ok, n, tag.constr, tag.class, tag.num)); break parse; } (ok, s.alg) = decode_algid(a[istart:n]); if(!ok) { if(X509_DEBUG) log("signed: alg identifier: syntax error"); break; } # signature (ok, tag, i, n) = der_dec1(a, n, len a); if(!ok || n != len a || tag.constr || tag.class != Universal || tag.num != BIT_STRING) { if(X509_DEBUG) log("signed: signature: " + sys->sprint("ok=%d, n=%d, constr=%d, class=%d, num=%d", ok, n, tag.constr, tag.class, tag.num)); break parse; } s.signature = a[i:n]; # to the end of no error been found return ("", s); } return ("signed: syntax error", nil);} # [public]# der encoding of signed data Signed.encode(s: self ref Signed): (string, array of byte){ (err, e_dat) := asn1->decode(s.tobe_signed); # why? if(err != "") return (err, nil); e_alg := pack_alg(s.alg); e_sig := ref Elem( Tag(Universal, BIT_STRING, 0), ref Value.BitString(0,s.signature) # DER encode of BIT STRING ); all := ref Elem( Tag(Universal, SEQUENCE, 1), ref Value.Seq(e_dat::e_alg::e_sig::nil) ); return asn1->encode(all);} # [public] Signed.sign(s: self ref Signed, sk: ref PrivateKey, hash: int): (string, array of byte){ # we require tobe_signed has 0 bits of padding if(int s.tobe_signed[0] != 0) return ("syntax error", nil); pick key := sk { RSA => (err, signature) := pkcs->rsa_sign(s.tobe_signed, key.sk, hash); s.signature = signature; # TODO: add AlgIdentifier based on public key and hash return (err, signature); DSS => # TODO: hash s.tobe_signed for signing (err, signature) := pkcs->dss_sign(s.tobe_signed, key.sk); s.signature = signature; return (err, signature); DH => return ("cannot sign using DH algorithm", nil); } return ("sign: failed", nil);} # [public]# hash algorithm should be MD2, MD4, MD5 or SHA Signed.verify(s: self ref Signed, pk: ref PublicKey, hash: int): int{ ok := 0; pick key := pk { RSA => ok = pkcs->rsa_verify(s.tobe_signed, s.signature, key.pk, hash); DSS => # TODO: hash s.tobe_signed for verifying ok = pkcs->dss_verify(s.tobe_signed, s.signature, key.pk); DH => # simply failure } return ok;} # [public] Signed.tostring(s: self ref Signed): string{ str := "Signed"; str += "\nToBeSigned: " + bastr(s.tobe_signed); str += "\nAlgorithm: " + s.alg.tostring(); str += "\nSignature: " + bastr(s.signature); return str + "\n";} # DER# a) the definite form of length encoding shall be used, encoded in the minimum number of # octets;# b) for string types, the constructed form of encoding shall not be used;# c) if the value of a type is its default value, it shall be absent;# d) the components of a Set type shall be encoded in ascending order of their tag value;# e) the components of a Set-of type shall be encoded in ascending order of their octet value;# f) if the value of a Boolean type is true, the encoding shall have its contents octet # set to "FF"16;# g) each unused bits in the final octet of the encoding of a Bit String value, if there are # any, shall be set to zero;# h) the encoding of a Real type shall be such that bases 8, 10, and 16 shall not be used, # and the binary scaling factor shall be zero. # [private]# decode ASN1 one record at a time and return (err, tag, start of data, # end of data) for indefinite length, the end of data is same as 'n' der_dec1(a: array of byte, i, n: int): (int, Tag, int, int){ length: int; tag: Tag; ok := 1; (ok, i, tag) = der_dectag(a, i, n); if(ok) { (ok, i, length) = der_declen(a, i, n); if(ok) { if(length == -1) { if(!tag.constr) ok = 0; length = n - i; } else { if(i+length > n) ok = 0; } } } if(!ok && X509_DEBUG) log("der_dec1: syntax error"); return (ok, tag, i, i+length);} # [private]# der tag decode der_dectag(a: array of byte, i, n: int): (int, int, Tag){ ok := 1; class, num, constr: int; if(n-i >= 2) { v := int a[i++]; class = v & CLASS_MASK; if(v & CONSTR_MASK) constr = 1; else constr = 0; num = v & TAG_MASK; if(num == TAG_MASK) # long tag number (ok, i, num) = uint7_decode(a, i, n); } else ok = 0; if(!ok && X509_DEBUG) log("der_declen: syntax error"); return (ok, i, Tag(class, num, constr));} # [private] int_decode(a: array of byte, i, n, count, unsigned: int): (int, int, int){ ok := 1; num := 0; if(n-i >= count) { if((count > 4) || (unsigned && count == 4 && (int a[i] & 16r80))) ok = 1; else { if(!unsigned && count > 0 && count < 4 && (int a[i] & 16r80)) num = -1; # all bits set for(j := 0; j < count; j++) { v := int a[i++]; num = (num << 8) | v; } } } else ok = 0; if(!ok && X509_DEBUG) log("int_decode: syntax error"); return (ok, i, num);} # [private] uint7_decode(a: array of byte, i, n: int) : (int, int, int){ ok := 1; num := 0; more := 1; while(more && i < n) { v := int a[i++]; if(num & 16r7F000000) { ok = 0; break; } num <<= 7; more = v & 16r80; num |= (v & 16r7F); } if(n == i) ok = 0; if(!ok && X509_DEBUG) log("uint7_decode: syntax error"); return (ok, i, num);} # [private]# der length decode - the definite form of length encoding shall be used, encoded # in the minimum number of octets der_declen(a: array of byte, i, n: int): (int, int, int){ ok := 1; num := 0; if(i < n) { v := int a[i++]; if(v & 16r80) return int_decode(a, i, n, v&16r7F, 1); else if(v == 16r80) # indefinite length ok = 0; else num = v; } else ok = 0; if(!ok && X509_DEBUG) log("der_declen: syntax error"); return (ok, i, num);} # [private]# parse der encoded algorithm identifier decode_algid(a: array of byte): (int, ref AlgIdentifier){ (err, el) := asn1->decode(a); if(err != "") { if(X509_DEBUG) log("decode_algid: " + err); return (0, nil); } return parse_alg(el);} ## TBS (Public Key) Certificate is signed by Certificate Authority and contains ## information of public key usage (as a comparison of Certificate Revocation List ## and Attribute Certificate). # [public]# constructs a certificate by parsing a der encoded certificate# returns error if parsing is failed or nil if parsing is ok certsyn(s: string): (string, ref Certificate){ if(0) sys->fprint(sys->fildes(2), "cert: %s\n", s); return ("certificate syntax: "+s, nil);} # Certificate ::= SEQUENCE {# certificateInfo CertificateInfo,# signatureAlgorithm AlgorithmIdentifier,# signature BIT STRING }## CertificateInfo ::= SEQUENCE {# version [0] INTEGER DEFAULT v1 (0),# serialNumber INTEGER,# signature AlgorithmIdentifier,# issuer Name,# validity Validity,# subject Name,# subjectPublicKeyInfo SubjectPublicKeyInfo }# (version v2 has two more fields, optional unique identifiers for# issuer and subject; since we ignore these anyway, we won't parse them)## Validity ::= SEQUENCE {# notBefore UTCTime,# notAfter UTCTime }## SubjectPublicKeyInfo ::= SEQUENCE {# algorithm AlgorithmIdentifier,# subjectPublicKey BIT STRING }## AlgorithmIdentifier ::= SEQUENCE {# algorithm OBJECT IDENTIFER,# parameters ANY DEFINED BY ALGORITHM OPTIONAL }## Name ::= SEQUENCE OF RelativeDistinguishedName## RelativeDistinguishedName ::= SETOF SIZE(1..MAX) OF AttributeTypeAndValue## AttributeTypeAndValue ::= SEQUENCE {# type OBJECT IDENTIFER,# value DirectoryString }# (selected attributes have these Object Ids:# commonName {2 5 4 3}# countryName {2 5 4 6}# localityName {2 5 4 7}# stateOrProvinceName {2 5 4 8}# organizationName {2 5 4 10}Lines 1–500 of 4125. Load more
implement X509; include "sys.m"; sys : Sys; include "asn1.m"; asn1 : ASN1; Elem, Tag, Value, Oid, Universal, Context, BOOLEAN, INTEGER, BIT_STRING, OCTET_STRING, OBJECT_ID, SEQUENCE, UTCTime, IA5String, GeneralString, GeneralizedTime : import asn1; include "keyring.m"; keyring : Keyring; IPint, DESstate : import keyring; include "security.m"; random : Random; include "daytime.m"; daytime : Daytime; include "pkcs.m"; pkcs : PKCS; include "x509.m"; X509_DEBUG : con 0; logfd : ref Sys->FD; TAG_MASK : con 16r1F; CONSTR_MASK : con 16r20; CLASS_MASK : con 16rC0; # object identifiers objIdTab = array [] of { id_at => Oid(array [] of {2,5,4}), id_at_commonName => Oid(array [] of {2,5,4,3}), id_at_countryName => Oid(array [] of {2,5,4,6}), id_at_localityName => Oid(array [] of {2,5,4,7}), id_at_stateOrProvinceName => Oid(array [] of {2,5,4,8}), id_at_organizationName => Oid(array [] of {2,5,4,10}), id_at_organizationalUnitName => Oid(array [] of {2,5,4,11}), id_at_userPassword => Oid(array [] of {2,5,4,35}), id_at_userCertificate => Oid(array [] of {2,5,4,36}), id_at_cAcertificate => Oid(array [] of {2,5,4,37}), id_at_authorityRevocationList => Oid(array [] of {2,5,4,38}), id_at_certificateRevocationList => Oid(array [] of {2,5,4,39}), id_at_crossCertificatePair => Oid(array [] of {2,5,4,40}), # id_at_crossCertificatePair => Oid(array [] of {2,5,4,58}), id_at_supportedAlgorithms => Oid(array [] of {2,5,4,52}), id_at_deltaRevocationList => Oid(array [] of {2,5,4,53}), id_ce => Oid(array [] of {2,5,29}), id_ce_subjectDirectoryAttributes => Oid(array [] of {2,5,29,9}), id_ce_subjectKeyIdentifier => Oid(array [] of {2,5,29,14}), id_ce_keyUsage => Oid(array [] of {2,5,29,15}), id_ce_privateKeyUsage => Oid(array [] of {2,5,29,16}), id_ce_subjectAltName => Oid(array [] of {2,5,29,17}), id_ce_issuerAltName => Oid(array [] of {2,5,29,18}), id_ce_basicConstraints => Oid(array [] of {2,5,29,19}), id_ce_cRLNumber => Oid(array [] of {2,5,29,20}), id_ce_reasonCode => Oid(array [] of {2,5,29,21}), id_ce_instructionCode => Oid(array [] of {2,5,29,23}), id_ce_invalidityDate => Oid(array [] of {2,5,29,24}), id_ce_deltaCRLIndicator => Oid(array [] of {2,5,29,27}), id_ce_issuingDistributionPoint => Oid(array [] of {2,5,29,28}), id_ce_certificateIssuer => Oid(array [] of {2,5,29,29}), id_ce_nameConstraints => Oid(array [] of {2,5,29,30}), id_ce_cRLDistributionPoint => Oid(array [] of {2,5,29,31}), id_ce_certificatePolicies => Oid(array [] of {2,5,29,32}), id_ce_policyMapping => Oid(array [] of {2,5,29,33}), id_ce_authorityKeyIdentifier => Oid(array [] of {2,5,29,35}), id_ce_policyConstraints => Oid(array [] of {2,5,29,36}), # id_mr => Oid(array [] of {2,5,?}), # id_mr_certificateMatch => Oid(array [] of {2,5,?,35}), # id_mr_certificatePairExactMatch => # Oid(array [] of {2,5,?,36}), # id_mr_certificatePairMatch => Oid(array [] of {2,5,?,37}), # id_mr_certificateListExactMatch => # Oid(array [] of {2,5,?,38}), # id_mr_certificateListMatch => Oid(array [] of {2,5,?,39}), # id_mr_algorithmidentifierMatch => # Oid(array [] of {2,5,?,40}) }; # [public] init(): string { sys = load Sys Sys->PATH; if(X509_DEBUG) logfd = sys->fildes(1); keyring = load Keyring Keyring->PATH; if(keyring == nil) return sys->sprint("load %s: %r", Keyring->PATH); random = load Random Random->PATH; if(random == nil) return sys->sprint("load %s: %r", Random->PATH); daytime = load Daytime Daytime->PATH; if(daytime == nil) return sys->sprint("load %s: %r", Daytime->PATH); asn1 = load ASN1 ASN1->PATH; if(asn1 == nil) return sys->sprint("load %s: %r", ASN1->PATH); asn1->init(); pkcs = load PKCS PKCS->PATH; if(pkcs == nil) return sys->sprint("load %s: %r", PKCS->PATH); if((e := pkcs->init()) != nil) return sys->sprint("pkcs: %s", e); return nil; } # [private] log(s: string) { if(X509_DEBUG) sys->fprint(logfd, "x509: %s\n", s); } ## SIGNED { ToBeSigned } ::= SEQUENCE { ## toBeSigned ToBeSigned, ## COMPONENTS OF SIGNATURE { ToBeSigned }} ## ## SIGNATURE {OfSignature} ::= SEQUENCE { ## algorithmIdentifier AlgorithmIdentifier, ## encrypted ENCRYPTED { HASHED { OfSignature }}} ## ## ENCRYPTED { ToBeEnciphered } ::= BIT STRING ( CONSTRAINED BY { ## -- must be the result of applying an encipherment procedure -- ## -- to the BER-encoded octets of a value of -- ToBeEnciphered } ) # [public] Signed.decode(a: array of byte): (string, ref Signed) { parse: for(;;) { # interpret the enclosing structure (ok, tag, i, n) := der_dec1(a, 0, len a); if(!ok || n != len a || !tag.constr || tag.class != Universal || tag.num != SEQUENCE) break parse; s := ref Signed; # SIGNED sequence istart := i; (ok, tag, i, n) = der_dec1(a, i, len a); if(!ok || n == len a) break parse; s.tobe_signed = a[istart:n]; # AlgIdentifier istart = n; (ok, tag, i, n) = der_dec1(a, n, len a); if(!ok || n == len a || !tag.constr || tag.class != Universal || tag.num != SEQUENCE) { if(X509_DEBUG) log("signed: der data: " + sys->sprint("ok=%d, n=%d, constr=%d, class=%d, num=%d", ok, n, tag.constr, tag.class, tag.num)); break parse; } (ok, s.alg) = decode_algid(a[istart:n]); if(!ok) { if(X509_DEBUG) log("signed: alg identifier: syntax error"); break; } # signature (ok, tag, i, n) = der_dec1(a, n, len a); if(!ok || n != len a || tag.constr || tag.class != Universal || tag.num != BIT_STRING) { if(X509_DEBUG) log("signed: signature: " + sys->sprint("ok=%d, n=%d, constr=%d, class=%d, num=%d", ok, n, tag.constr, tag.class, tag.num)); break parse; } s.signature = a[i:n]; # to the end of no error been found return ("", s); } return ("signed: syntax error", nil); } # [public] # der encoding of signed data Signed.encode(s: self ref Signed): (string, array of byte) { (err, e_dat) := asn1->decode(s.tobe_signed); # why? if(err != "") return (err, nil); e_alg := pack_alg(s.alg); e_sig := ref Elem( Tag(Universal, BIT_STRING, 0), ref Value.BitString(0,s.signature) # DER encode of BIT STRING ); all := ref Elem( Tag(Universal, SEQUENCE, 1), ref Value.Seq(e_dat::e_alg::e_sig::nil) ); return asn1->encode(all); } # [public] Signed.sign(s: self ref Signed, sk: ref PrivateKey, hash: int): (string, array of byte) { # we require tobe_signed has 0 bits of padding if(int s.tobe_signed[0] != 0) return ("syntax error", nil); pick key := sk { RSA => (err, signature) := pkcs->rsa_sign(s.tobe_signed, key.sk, hash); s.signature = signature; # TODO: add AlgIdentifier based on public key and hash return (err, signature); DSS => # TODO: hash s.tobe_signed for signing (err, signature) := pkcs->dss_sign(s.tobe_signed, key.sk); s.signature = signature; return (err, signature); DH => return ("cannot sign using DH algorithm", nil); } return ("sign: failed", nil); } # [public] # hash algorithm should be MD2, MD4, MD5 or SHA Signed.verify(s: self ref Signed, pk: ref PublicKey, hash: int): int { ok := 0; pick key := pk { RSA => ok = pkcs->rsa_verify(s.tobe_signed, s.signature, key.pk, hash); DSS => # TODO: hash s.tobe_signed for verifying ok = pkcs->dss_verify(s.tobe_signed, s.signature, key.pk); DH => # simply failure } return ok; } # [public] Signed.tostring(s: self ref Signed): string { str := "Signed"; str += "\nToBeSigned: " + bastr(s.tobe_signed); str += "\nAlgorithm: " + s.alg.tostring(); str += "\nSignature: " + bastr(s.signature); return str + "\n"; } # DER # a) the definite form of length encoding shall be used, encoded in the minimum number of # octets; # b) for string types, the constructed form of encoding shall not be used; # c) if the value of a type is its default value, it shall be absent; # d) the components of a Set type shall be encoded in ascending order of their tag value; # e) the components of a Set-of type shall be encoded in ascending order of their octet value; # f) if the value of a Boolean type is true, the encoding shall have its contents octet # set to "FF"16; # g) each unused bits in the final octet of the encoding of a Bit String value, if there are # any, shall be set to zero; # h) the encoding of a Real type shall be such that bases 8, 10, and 16 shall not be used, # and the binary scaling factor shall be zero. # [private] # decode ASN1 one record at a time and return (err, tag, start of data, # end of data) for indefinite length, the end of data is same as 'n' der_dec1(a: array of byte, i, n: int): (int, Tag, int, int) { length: int; tag: Tag; ok := 1; (ok, i, tag) = der_dectag(a, i, n); if(ok) { (ok, i, length) = der_declen(a, i, n); if(ok) { if(length == -1) { if(!tag.constr) ok = 0; length = n - i; } else { if(i+length > n) ok = 0; } } } if(!ok && X509_DEBUG) log("der_dec1: syntax error"); return (ok, tag, i, i+length); } # [private] # der tag decode der_dectag(a: array of byte, i, n: int): (int, int, Tag) { ok := 1; class, num, constr: int; if(n-i >= 2) { v := int a[i++]; class = v & CLASS_MASK; if(v & CONSTR_MASK) constr = 1; else constr = 0; num = v & TAG_MASK; if(num == TAG_MASK) # long tag number (ok, i, num) = uint7_decode(a, i, n); } else ok = 0; if(!ok && X509_DEBUG) log("der_declen: syntax error"); return (ok, i, Tag(class, num, constr)); } # [private] int_decode(a: array of byte, i, n, count, unsigned: int): (int, int, int) { ok := 1; num := 0; if(n-i >= count) { if((count > 4) || (unsigned && count == 4 && (int a[i] & 16r80))) ok = 1; else { if(!unsigned && count > 0 && count < 4 && (int a[i] & 16r80)) num = -1; # all bits set for(j := 0; j < count; j++) { v := int a[i++]; num = (num << 8) | v; } } } else ok = 0; if(!ok && X509_DEBUG) log("int_decode: syntax error"); return (ok, i, num); } # [private] uint7_decode(a: array of byte, i, n: int) : (int, int, int) { ok := 1; num := 0; more := 1; while(more && i < n) { v := int a[i++]; if(num & 16r7F000000) { ok = 0; break; } num <<= 7; more = v & 16r80; num |= (v & 16r7F); } if(n == i) ok = 0; if(!ok && X509_DEBUG) log("uint7_decode: syntax error"); return (ok, i, num); } # [private] # der length decode - the definite form of length encoding shall be used, encoded # in the minimum number of octets der_declen(a: array of byte, i, n: int): (int, int, int) { ok := 1; num := 0; if(i < n) { v := int a[i++]; if(v & 16r80) return int_decode(a, i, n, v&16r7F, 1); else if(v == 16r80) # indefinite length ok = 0; else num = v; } else ok = 0; if(!ok && X509_DEBUG) log("der_declen: syntax error"); return (ok, i, num); } # [private] # parse der encoded algorithm identifier decode_algid(a: array of byte): (int, ref AlgIdentifier) { (err, el) := asn1->decode(a); if(err != "") { if(X509_DEBUG) log("decode_algid: " + err); return (0, nil); } return parse_alg(el); } ## TBS (Public Key) Certificate is signed by Certificate Authority and contains ## information of public key usage (as a comparison of Certificate Revocation List ## and Attribute Certificate). # [public] # constructs a certificate by parsing a der encoded certificate # returns error if parsing is failed or nil if parsing is ok certsyn(s: string): (string, ref Certificate) { if(0) sys->fprint(sys->fildes(2), "cert: %s\n", s); return ("certificate syntax: "+s, nil); } # Certificate ::= SEQUENCE { # certificateInfo CertificateInfo, # signatureAlgorithm AlgorithmIdentifier, # signature BIT STRING } # # CertificateInfo ::= SEQUENCE { # version [0] INTEGER DEFAULT v1 (0), # serialNumber INTEGER, # signature AlgorithmIdentifier, # issuer Name, # validity Validity, # subject Name, # subjectPublicKeyInfo SubjectPublicKeyInfo } # (version v2 has two more fields, optional unique identifiers for # issuer and subject; since we ignore these anyway, we won't parse them) # # Validity ::= SEQUENCE { # notBefore UTCTime, # notAfter UTCTime } # # SubjectPublicKeyInfo ::= SEQUENCE { # algorithm AlgorithmIdentifier, # subjectPublicKey BIT STRING } # # AlgorithmIdentifier ::= SEQUENCE { # algorithm OBJECT IDENTIFER, # parameters ANY DEFINED BY ALGORITHM OPTIONAL } # # Name ::= SEQUENCE OF RelativeDistinguishedName # # RelativeDistinguishedName ::= SETOF SIZE(1..MAX) OF AttributeTypeAndValue # # AttributeTypeAndValue ::= SEQUENCE { # type OBJECT IDENTIFER, # value DirectoryString } # (selected attributes have these Object Ids: # commonName {2 5 4 3} # countryName {2 5 4 6} # localityName {2 5 4 7} # stateOrProvinceName {2 5 4 8} # organizationName {2 5 4 10}