123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151 |
- using Invercargill;
- using GnuTLS.X509;
- namespace Riddle {
- errordomain CertificateError {
- FAILURE
- }
- public class CertifiedNameInfo : NameInfo {
- private uint8[] raw_data { get; protected set; }
- private uint8[] data;
- private uint8[] signature;
-
- public override string get_encoded() {
- return Base64.encode(raw_data);
- }
- public CertifiedNameInfo.from_string(string encoded_name_info) throws NameInfoError{
- raw_data = Base64.decode(encoded_name_info);
- var stream = new MemoryInputStream.from_data(raw_data);
- var dis = new DataInputStream(stream);
- try{
- deserialise_data(dis);
- }
- catch (CertificateError e) {
- throw new NameInfoError.INVALID("A step in the X.509 verification step failed: " + e.message);
- }
- catch (Error e) {
- throw new NameInfoError.BAD_DATA("Error reading certified name information: " + e.message);
- }
- }
- public CertifiedNameInfo(string domain, PrivateKey key, Certificate cert, Certificate[] ca_chain, Enumerable<NameProperty> properties) throws Error {
- name = domain;
- effective = new DateTime.now_utc();
- expires = new DateTime.from_unix_utc(cert.get_expiration_time());
- this.properties = properties;
- var base_info = stringify_base_info();
- var base_data = as_datum(base_info.data);
- var signature = new uint8[5120];
- size_t sig_size = signature.length;
- check_result(key.sign_data(GnuTLS.DigestAlgorithm.SHA512, 0, ref base_data, signature, ref sig_size));
- signature.length = (int)sig_size;
- this.signature = signature;
- this.data = base_info.data;
- raw_data = serialise_data(cert, ca_chain);
- }
- private static GnuTLS.Datum as_datum(uint8[] data) {
- return GnuTLS.Datum() {
- data = data,
- size = data.length
- };
- }
- private uint8[] serialise_data(Certificate certificate, Certificate[] chain) {
- var stream = new MemoryOutputStream(null, GLib.realloc, GLib.free);
- var dos = new DataOutputStream(stream);
- dos.put_uint32(data.length);
- dos.put_uint32(signature.length);
- var cert = new uint8[5120];
- size_t cert_size = cert.length;
- check_result(certificate.export(CertificateFormat.DER, cert, ref cert_size));
- cert.length = (int)cert_size;
- dos.put_uint32(cert.length);
- dos.put_uint32(chain.length);
- dos.write(data);
- dos.write(signature);
- dos.write(cert);
- for(int i = 0; i < chain.length; i++) {
- cert = new uint8[5120];
- cert_size = cert.length;
- check_result(chain[i].export(CertificateFormat.DER, cert, ref cert_size));
- cert.length = (int)cert_size;
- dos.put_uint32(cert.length);
- dos.write(cert);
- }
- dos.flush();
- dos.close();
- var buffer = stream.steal_data();
- buffer.length = (int)stream.get_data_size();
- return buffer;
- }
- private void deserialise_data(DataInputStream stream) throws Error {
- var data_length = stream.read_uint32();
- var sig_length = stream.read_uint32();
- var cert_length = stream.read_uint32();
- var chain_count = stream.read_uint32();
-
- data = new uint8[data_length];
- stream.read(data);
- signature = new uint8[sig_length];
- stream.read(signature);
- var certificate_data = new uint8[cert_length];
- stream.read(certificate_data);
-
- var certificate_datum = as_datum(certificate_data);
- var certificate = Certificate.create();
- check_result(certificate.import(ref certificate_datum, CertificateFormat.DER));
- // TODO Idk how I'm supposed to handle chains yet
- // TODO verify
- var data_datum = as_datum(data);
- var sig_datum = as_datum(signature);
- check_result(certificate.verify_data2(get_algorithm(certificate), 0, ref data_datum, ref sig_datum));
- }
- private void check_result(int result) throws Error {
- if(result != 0) {
- throw new CertificateError.FAILURE(@"GnuTLS reported an error: $((GnuTLS.ErrorCode)result)");
- }
- }
- private static GnuTLS.SignAlgorithm get_algorithm(Certificate cert) {
- uint bits = 0;
- switch (cert.get_pk_algorithm(out bits)) {
- case GnuTLS.PKAlgorithm.DSA:
- return GnuTLS.SignAlgorithm.DSA_SHA512;
- case GnuTLS.PKAlgorithm.ECDSA:
- return GnuTLS.SignAlgorithm.ECDSA_SHA512;
- case GnuTLS.PKAlgorithm.RSA:
- return GnuTLS.SignAlgorithm.RSA_SHA512;
- default:
- return GnuTLS.SignAlgorithm.UNKNOWN;
- }
- }
- }
- }
|