Ver Fonte

Chaotic broken commit

Billy Barrow há 2 anos atrás
pai
commit
4a85fcdfbb

+ 31 - 0
README.md

@@ -1,3 +1,34 @@
 # Riddle
 
 A system for finding application peers and resolving names over mesh-like networks
+
+TODO:
+- Verify CertifiedNameInfo against system trust
+- Create a NameInfoStore, along with a FilesystemNameInfoStore and maybe a memory one too
+- Build propogation mechanism
+- Add propogation rate limit
+- Build tooling for generating and propogating NameInfo
+- Peer auto-discovery using LAN multicast, known seed servers, and optionally Yggdrasil nodeinfo (although this may not actually be needed)
+- Riddle (callback) mode, removing `CHALLENGE` requests.
+- OpenPGP domains, in the form `[fingerprint].rns` i.e. "c3a6-5e46-7b54-77df-3c4c-9790-4d22-b3ca-5b32-ff66.rns"
+- Server class should implement (or inherit) a "Service" class, with another implementation being "DaemonClient" when a Riddle Daemon is implemented
+
+## Riddles v2
+- Sent with `RIDDLE` request, accepted with `OK`
+- Responded to with `CALLBACK` request
+- Callback accepted with `SOLVED` reply
+- `RIDDLE` arguments: group id, ttl, expiry, reply port
+- `RIDDLE` items: checksum/id, riddle public key, author public key, reply public key, riddle data
+- `CALLBACK` arguments: riddle checksum/id
+- `CALLBACK` items: answer data, connecion info public key
+- `SOLVED` arguments: none
+- `SOLVED` items: encrypted and signed IP/port data
+
+- Riddles are sent to peers who are in the correct group
+- Peers receive the riddle and then forward onto other peers in the group - holding on to the riddle ID and metadata
+- When a peer is reached that can solve the riddle, it encrypts its answer with the `reply public key` and then signes the encrypted answer with the private key derrived from the riddle matching the `riddle public key`.
+- Thet peer then sends a `CALLBACK` request to the peer it received the riddle from.
+- The peer servicing the `CALLBACK` request verifies the riddle with the public signature, and if correct forwards the request to the peer it received the riddle from.
+- The originating peer once receiving and verifying the `CALLBACK` request, encrypts its IP/Port information with the `connection info public key` and then signs the encrypted data using the `author private key` from the riddle. The peer then replys with `SOLVED` and the encrypted/signed data.
+- Intermediate peers verify the `SOLVED` reply by verifying the encrypted data against the `author public key` of the riddle before passing back the reply.
+- At any point in the chain, if a peer is not happy it can reply with `NOT-ACCEPTED` and codes in the 1xx range.

+ 34 - 0
README.md.backup

@@ -0,0 +1,34 @@
+# Riddle
+
+A system for finding application peers and resolving names over mesh-like networks
+
+TODO:
+- Verify CertifiedNameInfo against system trust
+- Create a NameInfoStore, along with a FilesystemNameInfoStore and maybe a memory one too
+- Build propogation mechanism
+- Add propogation rate limit
+- Build tooling for generating and propogating NameInfo
+- Peer auto-discovery using LAN multicast, known seed servers, and optionally Yggdrasil nodeinfo (although this may not actually be needed)
+- Riddle (callback) mode, removing `CHALLENGE` requests.
+- OpenPGP domains, in the form `[fingerprint].rns` i.e. "c3a6-5e46-7b54-77df-3c4c-9790-4d22-b3ca-5b32-ff66.rns"
+- Server class should implement (or inherit) a "Service" class, with another implementation being "DaemonClient" when a Riddle Daemon is implemented
+
+## Riddles v2
+- Sent with `RIDDLE` request, accepted with `OK`
+- Responded to with `CALLBACK` request
+- Callback accepted with `SOLVED` reply
+- `RIDDLE` arguments: group id, ttl, expiry, reply port
+- `RIDDLE` items: checksum/id, riddle public key, reply public key, author public key, riddle data, n*challenge tokens
+- `CALLBACK` arguments: riddle checksum/id
+- `CALLBACK` items: n*signed tokens, answer data, connecion info public key
+- `SOLVED` arguments: none
+- `SOLVED` items: encrypted and signed IP/port data
+
+- Riddles are sent to peers who are in the correct group
+- Peers receive the riddle and then forward onto other peers in the group - holding on to the riddle ID and metadata
+- When a peer is reached that can solve the riddle, it encrypts its answer with the `reply public key` and then signes the encrypted answer with the private key derrived from the riddle matching the `riddle public key`.
+- Thet peer then sends a `CALLBACK` request to the peer it received the riddle from.
+- The peer servicing the `CALLBACK` request verifies the riddle with the public signature, and if correct forwards the request to the peer it received the riddle from.
+- The originating peer once receiving and verifying the `CALLBACK` request, encrypts its IP/Port information with the `connection info public key` and then signs the encrypted data using the `author private key` from the riddle. The peer then replys with `SOLVED` and the encrypted/signed data.
+- Intermediate peers verify the `SOLVED` reply by verifying the encrypted data against the `author public key` of the riddle before passing back the reply.
+- At any point in the chain, if a peer is not happy it can reply with `NOT-ACCEPTED` and codes in the 1xx range.

+ 0 - 23
src/lib/Answer.vala

@@ -1,23 +0,0 @@
-namespace Riddle {
-
-
-    public class Answer {
-
-        public string identifier { get; set; }
-        public uint8[] data { get; set; }
-
-        public Answer.from_arguments(string[] arguments) {
-            identifier = arguments[0];
-            data = Base64.decode (arguments[1]);
-        }
-
-        public string[] to_arguments() {
-            return new string[] {
-                identifier,
-                Base64.encode(data)
-            };
-        }
-
-    }
-
-}

+ 134 - 1
src/lib/CertifiedNameInfo.vala

@@ -1,17 +1,150 @@
 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);
         }
 
-        // TODO support for verifying using signed name info and verifying against system-trusted x.509 certificates
+        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;
+            }
+        }
 
     }
 

+ 0 - 22
src/lib/Challenge.vala

@@ -1,22 +0,0 @@
-namespace Riddle {
-
-
-    public class Challenge {
-
-        public string identifier { get; set; }
-        public uint8[] data { get; set; }
-
-        public Challenge.from_string(string challenge) {
-            var parts = challenge.split(" ", 2);
-            identifier = parts[0];
-            data = Base64.decode (parts[1]);
-        }
-
-        public string to_string() {
-            var encoded_data = Base64.encode(data);
-            return @"$identifier $encoded_data";
-        }
-
-    }
-
-}

+ 21 - 8
src/lib/DecentralisedNameInfo.vala

@@ -75,15 +75,15 @@ namespace Riddle {
             return @"$pk_enc:$sk_enc";
         }
 
+
+        private const int HASH_ROUNDS = 1048576;
         public static string generate_suffix(string root_name, uint8[] public_key) {
-            var checksum = new Checksum(ChecksumType.SHA512);
-            var name_data = root_name.data;
+            var current_data = root_name.data;
+            for(var i = 0; i < HASH_ROUNDS; i++) {
+                current_data = calculate_hash(current_data, public_key, ChecksumType.SHA512);
+            }
 
-            checksum.update(name_data, name_data.length);
-            checksum.update(public_key, public_key.length);
-            var digest = new uint8[64];
-            size_t size = digest.length;
-            checksum.get_digest(digest, ref size);
+            var digest = calculate_hash(current_data, public_key, ChecksumType.SHA256);
 
             var suffix = @".$(encode_hash(digest)).rns";
             return suffix;
@@ -94,11 +94,24 @@ namespace Riddle {
             return parts[parts.length - 3];
         }
 
+        private static uint8[] calculate_hash(uint8[] first, uint8[] second, ChecksumType type) {
+            var checksum = new Checksum(type);
+
+            checksum.update(first, first.length);
+            checksum.update(second, second.length);
+            var digest = new uint8[64];
+            size_t size = digest.length;
+            checksum.get_digest(digest, ref size);
+            digest.length = (int)size;
+
+            return digest;
+        }
+
         private const string ENCODING_CHARS = "abcdefghijklmnopqrstuvwxyz234567";
         private static string encode_hash(uint8[] data) {
             var s = new char[6];
             for(var i = 0; i < 6; i++) {
-                var v = data[i*10];
+                var v = data[i*5];
                 var ev = v / 8;
                 s[i] = ENCODING_CHARS[ev];
             }

+ 15 - 5
src/lib/Message.vala

@@ -9,12 +9,14 @@ namespace Riddle {
         PROPOGATE,
         WHO_IN,
         WHO_IS,
-        CHALLENGE,
+        RIDDLE,
+        CALLBACK,
 
         OK,
         ERROR,
         SEE_ALSO,
         ANSWER,
+        SOLVED,
         NOT_ACCEPTED,
         UNKNOWN;
 
@@ -30,8 +32,10 @@ namespace Riddle {
                     return MessageType.WHO_IN;
                 case "WHO-IS":
                     return MessageType.WHO_IS;
-                case "CHALLENGE":
-                    return MessageType.CHALLENGE;
+                case "RIDDLE":
+                    return MessageType.RIDDLE;
+                case "CALLBACK":
+                    return MessageType.CALLBACK;
                 case "OK":
                     return MessageType.OK;
                 case "ERROR":
@@ -40,6 +44,8 @@ namespace Riddle {
                     return MessageType.SEE_ALSO;
                 case "ANSWER":
                     return MessageType.ANSWER;
+                case "SOLVED":
+                    return MessageType.SOLVED;
                 case "NOT-ACCEPTED":
                     return MessageType.NOT_ACCEPTED;
                 case "UNKNOWN":
@@ -61,8 +67,10 @@ namespace Riddle {
                     return "WHO-IN";
                 case MessageType.WHO_IS:
                     return "WHO-IS";
-                case MessageType.CHALLENGE:
-                    return "CHALLENGE";
+                case MessageType.RIDDLE:
+                    return "RIDDLE";
+                case MessageType.CALLBACK:
+                    return "CALLBACK";
                 case MessageType.OK:
                     return  "OK";
                 case MessageType.ERROR:
@@ -71,6 +79,8 @@ namespace Riddle {
                     return "SEE-ALSO";
                 case MessageType.ANSWER:
                     return "ANSWER";
+                case MessageType.SOLVED:
+                    return "SOLVED";
                 case MessageType.NOT_ACCEPTED:
                     return "NOT-ACCEPTED";
                 case MessageType.UNKNOWN:

+ 23 - 0
src/lib/NameInfo.vala

@@ -50,6 +50,29 @@ namespace Riddle {
             }
         }
 
+        public string generate_checksum() {
+            var checksum = new Checksum(ChecksumType.SHA512);
+            var data = get_encoded();
+
+            checksum.update(Base64.decode(data), data.length);
+            var digest = new uint8[64];
+            size_t size = digest.length;
+            checksum.get_digest(digest, ref size);
+
+            return Base64.encode(digest);
+        }
+
+        public static bool verify_checksum(string data, string checksum) {
+            var cs = new Checksum(ChecksumType.SHA512);
+
+            cs.update(Base64.decode(data), data.length);
+            var digest = new uint8[64];
+            size_t size = digest.length;
+            cs.get_digest(digest, ref size);
+
+            return checksum == Base64.encode(digest);
+        }
+
     }
 
     public class NameProperty {

+ 65 - 10
src/lib/Riddle.vala

@@ -3,10 +3,59 @@ namespace Riddle {
     public abstract class Riddle {
 
         public InetSocketAddress application_address { get; set; }
+        public string group { get; protected set; }
+        public int max_hops { get; protected set; }
+        public int expiry_seconds { get; protected set; }
 
-        public abstract Challenge create_challenge();
-        public abstract Answer? answer_challenge(Challenge challenge);
-        public abstract InetSocketAddress? verify_answer(Challenge challenge, Answer answer);
+        private uint8[] riddle_verification_secret;
+        private uint8[] riddle_verification_key;
+
+        private uint8[] riddle_encryption_secret;
+        private uint8[] riddle_encryption_key;
+
+        private uint8[] author_signing_secret;
+        private uint8[] author_verification_key;
+
+        public RiddleEnvelope seal(uint reply_port) {
+            var data = generate(riddle_verification_secret);
+            var envelope = new RiddleEnvelope() {
+                group_name = group,
+                ttl = 10,
+                expiry = new DateTime.now_utc().add_seconds(expiry_seconds),
+                reply_port = reply_port,
+                solution_verification_key = riddle_verification_key.copy(),
+                solution_encryption_key = riddle_encryption_key.copy(),
+                author_signing_key = author_verification_key.copy(),
+                data = data
+            };
+
+            envelope.identifier = envelope.generate_identifier();
+            return envelope;
+        }
+
+        public Message mark_solution(SolutionEnvelope envelope) {
+            if(!envelope.verify(riddle_verification_key)) {
+                return new Message(MessageType.NOT_ACCEPTED, new string[] { "101", "verification-failed" }, new string[0]);
+            }
+
+            var solution = unseal_solution(envelope);
+            if(solution == null) {
+                return new Message(MessageType.NOT_ACCEPTED, new string[] { "102", "decryption-failed" }, new string[0]);
+            }
+
+            var contact_info = validate(solution.data);
+            if(contact_info == null) {
+                return new Message(MessageType.NOT_ACCEPTED, new string[] { "100", "validation-failed" }, new string[0]);
+            }
+
+            var encrypted_contact_info = solution.encrypt_connection_details(contact_info);
+            var signed_contact_info = Sodium.Asymmetric.Signing.sign(encrypted_contact_info, author_signing_secret);
+            return new Message(MessageType.SOLVED, new string[0], new string[] { Base64.encode(signed_contact_info) });
+        }
+
+        protected abstract uint8[] generate(uint8[] secret);
+        protected abstract InetSocketAddress? validate(uint8[] solution);
+        public abstract uint8[]? solve(uint8[] riddle);
 
         protected uint8[] join_data(uint8[] payload, uint8[] to_add) {
             var new_payload = new uint8[payload.length + to_add.length];
@@ -22,14 +71,20 @@ namespace Riddle {
             return new_payload;
         }
 
-        protected uint8[] serialise_address() {
-            var s = @"$(application_address.address) $(application_address.port)";
-            return s.data;
-        }
+        private Solution? unseal_solution(SolutionEnvelope envelope) {
+            var encrypted_data = Sodium.Asymmetric.Signing.verify(envelope.signed_data, riddle_verification_key);
+            var encrypted_reply_key = Sodium.Asymmetric.Signing.verify(envelope.signed_reply_key, riddle_verification_key);
+            if(encrypted_data == null || encrypted_reply_key == null) {
+                return null;
+            }
+
+            var data = Sodium.Asymmetric.Sealing.unseal(encrypted_data, riddle_encryption_key, riddle_encryption_secret);
+            var reply_key = Sodium.Asymmetric.Sealing.unseal(encrypted_reply_key, riddle_encryption_key, riddle_encryption_secret);
+            if(data == null || reply_key == null) {
+                return null;
+            }
 
-        protected InetSocketAddress deserialise_address(uint8[] data) {
-            var parts = ((string)data).split(" ", 2);
-            return new InetSocketAddress.from_string(parts[0], uint.parse(parts[1]));
+            return new Solution(data, reply_key);
         }
 
     }

+ 100 - 0
src/lib/RiddleEnvelope.vala

@@ -0,0 +1,100 @@
+using Invercargill;
+
+namespace Riddle {
+
+
+    public class RiddleEnvelope {
+
+        public string group_name { get; set; }
+        public int ttl { get; set; }
+        public DateTime expiry { get; set; }
+        public uint reply_port { get; set; }
+        public InetAddress? reply_address { get; set; }
+        public string identifier { get; set; }
+        public uint8[] solution_verification_key { get; set; }
+        public uint8[] solution_encryption_key { get; set; }
+        public uint8[] author_signing_key { get; set; }
+        public uint8[] data { get; set; }
+
+        public RiddleEnvelope.from_message(Message message, InetAddress reply_address) {
+            
+            this.reply_address = reply_address;
+
+            group_name = message.arguments[0];
+            ttl = int.parse (message.arguments[1]);
+            expiry = new DateTime.from_iso8601 (message.arguments[2], null);
+            reply_port = uint.parse (message.arguments[3]);
+
+            identifier = message.items[0];
+            solution_verification_key = Base64.decode (message.items[1]);
+            solution_encryption_key = Base64.decode (message.items[2]);
+            author_signing_key = Base64.decode (message.items[3]);
+
+            data = Base64.decode (message.items[4]);
+        }
+
+        public RiddleEnvelope? forward(uint reply_port) {
+            if(ttl <= 0) {
+                return null;
+            }
+
+            var token = new uint8[1024];
+            Sodium.Random.random_bytes(token);
+
+            return new RiddleEnvelope() {
+                group_name = group_name,
+                ttl = ttl - 1,
+                expiry = expiry,
+                reply_port = reply_port,
+                identifier = identifier,
+                solution_verification_key = solution_verification_key.copy(),
+                solution_encryption_key = _solution_encryption_key.copy(),
+                author_signing_key = author_signing_key.copy(),
+                data = data.copy(),
+            };
+        }
+
+        public bool validate_identifier() {
+            return generate_identifier() == identifier;
+        }
+
+        public Message to_message() {
+            return new Message(MessageType.RIDDLE, 
+                new string[] {
+                    group_name,
+                    ttl.to_string(),
+                    expiry.format_iso8601(),
+                    reply_port.to_string()
+                },
+                new string[] {
+                    identifier,
+                    Base64.encode(solution_verification_key),
+                    Base64.encode(solution_encryption_key),
+                    Base64.encode(author_signing_key),
+                    Base64.encode(data),
+                }
+            );
+        }
+
+        public void compact() {
+            data = null;
+        }
+
+        internal string generate_identifier() {
+            var checksum = new Checksum(ChecksumType.SHA512);
+            checksum.update(data, data.length);
+            checksum.update(solution_verification_key, solution_verification_key.length);
+            checksum.update(solution_encryption_key, solution_encryption_key.length);
+            checksum.update(author_signing_key, author_signing_key.length);
+            
+            var digest = new uint8[64];
+            size_t size = digest.length;
+            checksum.get_digest(digest, ref size);
+            digest.length = (int)size;
+
+            return Base64.encode(digest);
+        }
+
+    }
+
+}

+ 9 - 9
src/lib/Server.vala

@@ -7,7 +7,7 @@ namespace Riddle {
         public const int REGISTRATION_TIMEOUT_US = 600000000;
         private SocketService service;
         private Gee.HashMap<string, Invercargill.Sequence<Registration>> registrations = new Gee.HashMap<string, Invercargill.Sequence<Registration>>();
-        private Gee.HashMap<string, Invercargill.Sequence<Riddle>> riddles = new Gee.HashMap<string, Invercargill.Sequence<Riddle>>();
+        private Gee.HashMap<string, Invercargill.Sequence<RiddleEnvelope>> riddles = new Gee.HashMap<string, Invercargill.Sequence<RiddleEnvelope>>();
         private Gee.HashMap<string, NameInfo> names = new Gee.HashMap<string, NameInfo>();
         
         
@@ -60,8 +60,8 @@ namespace Riddle {
                     return handle_who_in(msg);
                 case MessageType.WHO_IS:
                     return handle_who_is(msg);
-                case MessageType.CHALLENGE:
-                    return handle_challenge(msg);
+                case MessageType.RIDDLE:
+                    return handle_riddle(msg);
                 default:
                     return new Message(MessageType.ERROR, new string[] { "unknown-command" }, new string[0]);
             }
@@ -99,10 +99,10 @@ namespace Riddle {
                 if(name.has_suffix(".rns")) {
                     var name_info = new DecentralisedNameInfo.from_string(encoded_name_info);
                     if(name_info.name != name) {
-                        return new Message(MessageType.NOT_ACCEPTED, new string[] { "100", "name-mismatch" }, new string[0]);
+                        return new Message(MessageType.NOT_ACCEPTED, new string[] { "200", "name-mismatch" }, new string[0]);
                     }
                     if(!add_name_info_if_latest(name_info)) {
-                        return new Message(MessageType.NOT_ACCEPTED, new string[] { "104", "outdated" }, new string[0]);
+                        return new Message(MessageType.NOT_ACCEPTED, new string[] { "205", "outdated" }, new string[0]);
                     }
                 }
                 else {
@@ -111,13 +111,13 @@ namespace Riddle {
                 }
             }
             catch(NameInfoError.BAD_DATA e) {
-                return new Message(MessageType.NOT_ACCEPTED, new string[] { "101", "malformed-information" }, new string[0]);
+                return new Message(MessageType.NOT_ACCEPTED, new string[] { "201", "malformed-information" }, new string[0]);
             }
             catch(NameInfoError.INVALID e) {
-                return new Message(MessageType.NOT_ACCEPTED, new string[] { "102", "invalid-information" }, new string[0]);
+                return new Message(MessageType.NOT_ACCEPTED, new string[] { "202", "invalid-information" }, new string[0]);
             }
             catch(NameInfoError.NOT_IN_DATE e) {
-                return new Message(MessageType.NOT_ACCEPTED, new string[] { "103", "outside-date-range" }, new string[0]);
+                return new Message(MessageType.NOT_ACCEPTED, new string[] { "203", "outside-date-range" }, new string[0]);
             }
 
             return new Message(MessageType.OK, new string[0], new string[0]);
@@ -137,7 +137,7 @@ namespace Riddle {
             return new Message(MessageType.ANSWER, new string[0], new string[] { name.get_encoded() });
         }
 
-        private Message handle_challenge(Message msg) throws Error {
+        private Message handle_riddle(Message msg) throws Error {
             var group_id = msg.arguments[0];
             var riddles_to_try = Invercargill.empty<Riddle>();
             lock(riddles) {

+ 37 - 0
src/lib/Solution.vala

@@ -0,0 +1,37 @@
+namespace Riddle {
+
+
+    public sealed class Solution {
+
+        public uint8[] data { get; private set; }
+        public uint8[] reply_key { get; private set; }
+
+        public Solution(uint8[] data, uint8[] reply_public_key) {
+            this.data = data;
+            reply_key = reply_public_key;
+        }
+
+        public uint8[] encrypt_connection_details(InetSocketAddress address) {
+            var serialised = serialise_address(address);
+            return Sodium.Asymmetric.Sealing.seal(serialised, reply_key);
+        }
+
+        private uint8[] serialise_address(InetSocketAddress address) {
+            var s = @"$(address.address) $(address.port)";
+            return s.data;
+        }
+
+        public SolutionEnvelope seal(string riddle_id, uint8[] riddle_secret, uint8[] riddle_encryption_key) {
+            var encrypted_data = Sodium.Asymmetric.Sealing.seal(data, riddle_encryption_key);
+            var encrypted_reply_key = Sodium.Asymmetric.Sealing.seal(reply_key, riddle_encryption_key);
+
+            return new SolutionEnvelope() {
+                identifier = riddle_id,
+                signed_data = Sodium.Asymmetric.Signing.sign(encrypted_data, riddle_secret),
+                signed_reply_key = Sodium.Asymmetric.Signing.sign(encrypted_reply_key, riddle_secret)
+            };
+        }
+
+    }
+
+}

+ 39 - 0
src/lib/SolutionEnvelope.vala

@@ -0,0 +1,39 @@
+namespace Riddle {
+
+
+    public class SolutionEnvelope {
+
+        public string identifier { get; set; }
+        public uint8[] signed_data { get; set; }
+        public uint8[] signed_reply_key { get; set; }
+
+        public SolutionEnvelope.from_message(Message message) {
+            
+            identifier = message.arguments[0];
+            
+            signed_data = Base64.decode (message.items[0]);
+            signed_reply_key = Base64.decode (message.items[1]);
+        }
+
+        public bool verify(uint8[] verification_key) {
+            var d1 = Sodium.Asymmetric.Signing.verify(signed_data, verification_key);
+            var d2 = Sodium.Asymmetric.Signing.verify(signed_reply_key, verification_key);
+            return d1 != null && d2 != null;
+        }
+
+        public Message to_message() {
+            return new Message(MessageType.RIDDLE, 
+                new string[] {
+                    identifier
+                },
+                new string[] {
+                    identifier,
+                    Base64.encode(signed_data),
+                    Base64.encode(signed_reply_key)
+                }
+            );
+        }
+
+    }
+
+}

+ 5 - 3
src/lib/meson.build

@@ -8,18 +8,20 @@ dependencies = [
     dependency('gio-2.0'),
     dependency('gee-0.8'),
     dependency('invercargill'),
-    dependency('gnutls'),
     meson.get_compiler('vala').find_library('libsodium', dirs: vapi_dir),
+    meson.get_compiler('vala').find_library('gnutls', dirs: vapi_dir),
     meson.get_compiler('c').find_library('sodium'),
+    meson.get_compiler('c').find_library('gnutls'),
     meson.get_compiler('c').find_library('m')
 ]
 
 sources = files('Riddle.vala')
+sources += files('RiddleEnvelope.vala')
 sources += files('SharedKeyPairRiddle.vala')
 sources += files('IdentityRiddle.vala')
 sources += files('Message.vala')
-sources += files('Answer.vala')
-sources += files('Challenge.vala')
+sources += files('Solution.vala')
+sources += files('SolutionEnvelope.vala')
 sources += files('Server.vala')
 sources += files('Client.vala')
 sources += files('NameInfo.vala')

+ 1944 - 0
src/lib/vapi/gnutls.vapi

@@ -0,0 +1,1944 @@
+/* gnutls.vapi
+ *
+ * Copyright (C) 2009  Jiří Zárevúcky
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA
+ *
+ * As a special exception, if you use inline functions from this file, this
+ * file does not by itself cause the resulting executable to be covered by
+ * the GNU Lesser General Public License.
+ *
+ * Author:
+ * 	Jiří Zárevúcky <zarevucky.jiri@gmail.com>
+ *  Lazily updated by Billy Barrow in 2023
+ *
+ */
+
+ [CCode (cprefix = "gnutls_", lower_case_cprefix = "gnutls_", cheader_filename = "gnutls/gnutls.h")]
+ namespace GnuTLS
+ {
+     [CCode (cname = "LIBGNUTLS_VERSION")]
+     public const string VERSION;
+     [CCode (cname = "LIBGNUTLS_VERSION_MAJOR")]
+     public const int VERSION_MAJOR;
+     [CCode (cname = "LIBGNUTLS_VERSION_MINOR")]
+     public const int VERSION_MINOR;
+     [CCode (cname = "LIBGNUTLS_VERSION_PATCH")]
+     public const int VERSION_PATCH;
+     [CCode (cname = "LIBGNUTLS_VERSION_NUMBER")]
+     public const int VERSION_NUMBER;
+ 
+     public unowned string? check_version (string? req_version);
+ 
+     [CCode (cname = "gnutls_cipher_algorithm_t", cprefix = "GNUTLS_CIPHER_", has_type_id = false)]
+     public enum CipherAlgorithm {
+         UNKNOWN,
+         NULL,
+         ARCFOUR_128,
+         3DES_CBC,
+         AES_128_CBC,
+         AES_256_CBC,
+         ARCFOUR_40,
+         CAMELLIA_128_CBC,
+         CAMELLIA_256_CBC,
+         RC2_40_CBC,
+         DES_CBC,
+ 
+         RIJNDAEL_128_CBC,    // == AES_128_CBC
+         RIJNDAEL_256_CBC,    // == AES_256_CBC
+         RIJNDAEL_CBC,        // == AES_128_CBC
+         ARCFOUR;             // == ARCFOUR_128
+ 
+         [CCode (cname = "gnutls_cipher_get_key_size")]
+         public size_t get_key_size ();
+         [CCode (cname = "gnutls_cipher_get_name")]
+         public unowned string? get_name ();
+         [CCode (cname = "gnutls_mac_get_id")]
+         public static CipherAlgorithm from_name (string name);
+         [CCode (cname = "gnutls_cipher_list", array_length = "false", array_null_terminated = "true")]
+         public static unowned CipherAlgorithm[] list ();
+     }
+ 
+     [CCode (cname = "gnutls_kx_algorithm_t", cprefix = "GNUTLS_KX_", has_type_id = false)]
+     public enum KXAlgorithm	{
+         UNKNOWN,
+         RSA,
+         DHE_DSS,
+         DHE_RSA,
+         ANON_DH,
+         SRP,
+         RSA_EXPORT,
+         SRP_RSA,
+         SRP_DSS,
+         PSK,
+         DHE_PSK;
+ 
+         [CCode (cname = "gnutls_kx_get_name")]
+         public unowned string? get_name ();
+         [CCode (cname = "gnutls_kx_get_id")]
+         public static KXAlgorithm from_name (string name);
+         [CCode (cname = "gnutls_kx_list", array_length = "false", array_null_terminated = "true")]
+         public static unowned KXAlgorithm[] list ();
+     }
+ 
+     [CCode (cname = "gnutls_mac_algorithm_t", cprefix = "GNUTLS_MAC_", has_type_id = false)]
+     public enum MacAlgorithm {
+         UNKNOWN,
+         NULL,
+         MD5,
+         SHA1,
+         RMD160,
+         MD2,
+         SHA256,
+         SHA384,
+         SHA512;
+ 
+         [CCode (cname = "gnutls_mac_get_key_size")]
+         public size_t get_key_size ();
+         [CCode (cname = "gnutls_mac_get_name")]
+         public unowned string? get_name ();
+         [CCode (cname = "gnutls_mac_get_id")]
+         public static MacAlgorithm from_name (string name);
+         [CCode (cname = "gnutls_mac_list", array_length = "false", array_null_terminated = "true")]
+         public static unowned MacAlgorithm[] list ();
+     }
+ 
+     [CCode (cname = "gnutls_digest_algorithm_t", cprefix = "GNUTLS_DIG_", has_type_id = false)]
+     public enum DigestAlgorithm {
+         NULL,
+         MD5,
+         SHA1,
+         RMD160,
+         MD2,
+         SHA224,
+         SHA256,
+         SHA384,
+         SHA512;
+ 
+         [CCode (cname = "gnutls_fingerprint")]
+         public int fingerprint (/* const */ ref Datum data, void* result, ref size_t result_size);
+     }
+ 
+     [CCode (cname = "GNUTLS_MAX_ALGORITHM_NUM")]
+     public const int MAX_ALGORITHM_NUM;
+ 
+     [CCode (cname = "gnutls_pk_algorithm_t", cprefix = "GNUTLS_PK_", has_type_id = false)]
+     public enum PKAlgorithm {
+        UNKNOWN,
+        RSA,
+        DSA,
+        DH,
+        ECDSA,
+        ECDH_X25519,
+        RSA_PSS,
+        EDDSA_ED25519,
+        GOST_01,
+        GOST_12_256,
+        GOST_12_512,
+        ECDH_X448,
+        EDDSA_ED448,
+        MAX;
+ 
+         [CCode (cname = "gnutls_pk_algorithm_get_name")]
+         public unowned string? get_name ();
+     }
+ 
+     [CCode (cname = "gnutls_sign_algorithm_t", cprefix = "GNUTLS_SIGN_", has_type_id = false)]
+     public enum SignAlgorithm {
+        UNKNOWN,
+        RSA_SHA1,
+        RSA_SHA,
+        DSA_SHA1,
+        DSA_SHA,
+        RSA_MD5,
+        RSA_MD2,
+        RSA_RMD160,
+        RSA_SHA256,
+        RSA_SHA384,
+        RSA_SHA512,
+        RSA_SHA224,
+        DSA_SHA224,
+        DSA_SHA256,
+        ECDSA_SHA1,
+        ECDSA_SHA224,
+        ECDSA_SHA256,
+        ECDSA_SHA384,
+        ECDSA_SHA512,
+        DSA_SHA384,
+        DSA_SHA512,
+        ECDSA_SHA3_224,
+        ECDSA_SHA3_256,
+        ECDSA_SHA3_384,
+        ECDSA_SHA3_512,
+        DSA_SHA3_224,
+        DSA_SHA3_256,
+        DSA_SHA3_384,
+        DSA_SHA3_512,
+        RSA_SHA3_224,
+        RSA_SHA3_256,
+        RSA_SHA3_384,
+        RSA_SHA3_512,
+        RSA_PSS_SHA256,
+        RSA_PSS_SHA384,
+        RSA_PSS_SHA512,
+        EDDSA_ED25519,
+        RSA_RAW,
+        ECDSA_SECP256R1_SHA256,
+        ECDSA_SECP384R1_SHA384,
+        ECDSA_SECP521R1_SHA512,
+        RSA_PSS_RSAE_SHA256,
+        RSA_PSS_RSAE_SHA384,
+        RSA_PSS_RSAE_SHA512,
+        GOST_94,
+        GOST_256,
+        GOST_512,
+        EDDSA_ED448,
+        MAX;
+ 
+         [CCode (cname = "gnutls_sign_algorithm_get_name")]
+         public unowned string? get_name ();
+     }
+ 
+     [CCode (cname = "gnutls_compression_method_t", cprefix = "GNUTLS_COMP_", has_type_id = false)]
+     public enum CompressionMethod {
+         UNKNOWN,
+         NULL,
+         DEFLATE,
+         ZLIB,     // == DEFLATE
+         LZO;      // only available if gnutls-extra has been initialized
+ 
+         [CCode (cname = "gnutls_compression_get_name")]
+         public unowned string? get_name ();
+         [CCode (cname = "gnutls_compression_get_id")]
+         public static CompressionMethod from_name (string name);
+         [CCode (cname = "gnutls_compression_list", array_length = "false", array_null_terminated = "true")]
+         public static unowned CompressionMethod[] list ();
+     }
+ 
+     [CCode (cname = "gnutls_params_type_t", cprefix = "GNUTLS_PARAMS_", has_type_id = false)]
+     public enum ParamsType {
+         RSA_EXPORT,
+         DH
+     }
+ 
+     [CCode (cname = "gnutls_credentials_type_t", cprefix = "GNUTLS_CRD_", has_type_id = false)]
+     public enum CredentialsType {
+         CERTIFICATE,
+         ANON,
+         SRP,
+         PSK,
+         IA
+     }
+ 
+     [CCode (cname = "gnutls_alert_level_t", cprefix = "GNUTLS_AL_", has_type_id = false)]
+     public enum AlertLevel {
+         WARNING,
+         FATAL
+     }
+ 
+     [CCode (cname = "gnutls_alert_description_t", cprefix = "GNUTLS_A_", has_type_id = false)]
+     public enum AlertDescription {
+         CLOSE_NOTIFY,
+         UNEXPECTED_MESSAGE,
+         BAD_RECORD_MAC,
+         DECRYPTION_FAILED,
+         RECORD_OVERFLOW,
+         DECOMPRESSION_FAILURE,
+         HANDSHAKE_FAILURE,
+         SSL3_NO_CERTIFICATE,
+         BAD_CERTIFICATE,
+         UNSUPPORTED_CERTIFICATE,
+         CERTIFICATE_REVOKED,
+         CERTIFICATE_EXPIRED,
+         CERTIFICATE_UNKNOWN,
+         ILLEGAL_PARAMETER,
+         UNKNOWN_CA,
+         ACCESS_DENIED,
+         DECODE_ERROR,
+         DECRYPT_ERROR,
+         EXPORT_RESTRICTION,
+         PROTOCOL_VERSION,
+         INSUFFICIENT_SECURITY,
+         INTERNAL_ERROR,
+         USER_CANCELED,
+         NO_RENEGOTIATION,
+         UNSUPPORTED_EXTENSION,
+         CERTIFICATE_UNOBTAINABLE,
+         UNRECOGNIZED_NAME,
+         UNKNOWN_PSK_IDENTITY,
+         INNER_APPLICATION_FAILURE,
+         INNER_APPLICATION_VERIFICATION;
+ 
+         [CCode (cname = "gnutls_alert_get_name")]
+         public unowned string? get_name ();
+     }
+ 
+     [CCode (cname = "gnutls_handshake_description_t", cprefix = "GNUTLS_HANDSHAKE_", has_type_id = false)]
+     public enum HandshakeDescription {
+         HELLO_REQUEST,
+         CLIENT_HELLO,
+         SERVER_HELLO,
+         CERTIFICATE_PKT,
+         SERVER_KEY_EXCHANGE,
+         CERTIFICATE_REQUEST,
+         SERVER_HELLO_DONE,
+         CERTIFICATE_VERIFY,
+         CLIENT_KEY_EXCHANGE,
+         FINISHED,
+         SUPPLEMENTAL
+     }
+ 
+     /* Note that the status bits have different meanings
+      * in openpgp keys and x.509 certificate verification.
+      */
+     [Flags]
+     [CCode (cname = "gnutls_certificate_status_t", cprefix = "GNUTLS_CERT_", has_type_id = false)]
+     public enum CertificateStatus {
+         INVALID,             // will be set if the certificate was not verified.
+         REVOKED,             // in X.509 this will be set only if CRLs are checked
+         SIGNER_NOT_FOUND,
+         SIGNER_NOT_CA,
+         INSECURE_ALGORITHM
+     }
+ 
+     [CCode (cname = "gnutls_certificate_request_t", cprefix = "GNUTLS_CERT_", has_type_id = false)]
+     public enum CertificateRequest {
+         IGNORE,
+         REQUEST,
+         REQUIRE
+     }
+ 
+ //	[CCode (cname = "gnutls_openpgp_crt_status_t", cprefix = "GNUTLS_OPENPGP_", has_type_id = false)]
+ //	public enum OpenPGP.CertificateStatus {
+ //		CERT,
+ //		CERT_FINGERPRINT
+ //	}
+ //
+ //	[CCode (cname = "gnutls_connection_end_t", cprefix = "GNUTLS_", has_type_id = false)]
+ //	public enum ConnectionEnd {
+ //		SERVER,
+ //		CLIENT
+ //	}
+ 
+     [CCode (cname = "gnutls_close_request_t", cprefix = "GNUTLS_SHUT_", has_type_id = false)]
+     public enum CloseRequest {
+         RDWR,
+         WR
+     }
+ 
+     [CCode (cname = "gnutls_protocol_t", cprefix = "GNUTLS_", has_type_id = false)]
+     public enum Protocol {
+         SSL3,
+         TLS1,    // == TLS1_0
+         TLS1_0,
+         TLS1_1,
+         TLS1_2,
+         [CCode (cname = "GNUTLS_VERSION_UNKNOWN")]
+         UNKNOWN;
+ 
+         [CCode (cname = "gnutls_protocol_get_name")]
+         public unowned string? get_name ();
+         [CCode (cname = "gnutls_protocol_get_id")]
+         public static Protocol from_name (string name);
+         [CCode (cname = "gnutls_protocol_list", array_length = "false", array_null_terminated = "true")]
+         public static unowned Protocol[] list ();
+     }
+ 
+     [CCode (cname = "gnutls_certificate_type_t", cprefix = "GNUTLS_CRT_", has_type_id = false)]
+     public enum CertificateType {
+         UNKNOWN,
+         X509,
+         OPENPGP;
+ 
+         [CCode (cname = "gnutls_certificate_type_get_name")]
+         public unowned string? get_name ();
+         [CCode (cname = "gnutls_certificate_type_get_id")]
+         public static CertificateType from_name (string name);
+         [CCode (cname = "gnutls_certificate_type_list", array_length = "false", array_null_terminated = "true")]
+         public static unowned CertificateType[] list ();
+     }
+ 
+     [CCode (cname = "gnutls_certificate_print_formats_t", cprefix = "GNUTLS_CRT_PRINT_", has_type_id = false)]
+     public enum CertificatePrintFormats {
+         FULL,
+         ONELINE,
+         UNSIGNED_FULL
+     }
+ 
+     [Flags]
+     [CCode (cname = "unsigned int", cprefix = "GNUTLS_KEY_", has_type_id = false)]
+     public enum KeyUsage
+     {
+         DIGITAL_SIGNATURE,
+         NON_REPUDIATION,
+         KEY_ENCIPHERMENT,
+         DATA_ENCIPHERMENT,
+         KEY_AGREEMENT,
+         KEY_CERT_SIGN,
+         CRL_SIGN,
+         ENCIPHER_ONLY,
+         DECIPHER_ONLY
+     }
+ 
+     [CCode (cname = "gnutls_server_name_type_t", cprefix = "GNUTLS_NAME_", has_type_id = false)]
+     public enum ServerNameType {
+         DNS;
+     }
+ 
+     // Diffie Hellman parameter handling.
+     [Compact]
+     [CCode (cname = "struct gnutls_dh_params_int", free_function = "gnutls_dh_params_deinit", lower_case_cprefix = "gnutls_dh_params_")]
+     public class DHParams {
+         private static int init (out DHParams dh_params);
+         public static DHParams create ()
+         {
+             DHParams result;
+             var ret = init (out result);
+             if (ret != 0)
+                 GLib.error ("%s", ((ErrorCode)ret).to_string ());
+             return result;
+         }
+ 
+         private int cpy (DHParams source);
+ 
+         public int import_raw (/* const */ ref Datum prime, /* const */ ref Datum generator);
+         public int export_raw (/* const */ ref Datum prime, /* const */ ref Datum generator, out uint bits);
+         public int import_pkcs3 (/* const */ ref Datum pkcs3_params, X509.CertificateFormat format);
+         public int export_pkcs3 (X509.CertificateFormat format, void* params_data, ref size_t params_data_size);
+ 
+         [CCode (cname = "gnutls_dh_params_generate2")]
+         public int generate (uint bits);
+     }
+ 
+     [Compact]
+     [CCode (cname = "struct gnutls_x509_privkey_int", free_function = "gnutls_rsa_params_deinit", lower_case_cprefix = "gnutls_rsa_params_")]
+     public class RSAParams {
+         private static int init (out RSAParams dh_params);
+         public static RSAParams create ()
+         {
+             RSAParams result = null;
+             var ret = init (out result);
+             if (ret != 0)
+                 GLib.error ("%s", ((ErrorCode)ret).to_string ());
+             return result;
+         }
+ 
+         private int cpy (RSAParams source);
+ 
+         public int import_raw (/* const */ ref Datum m, /* const */ ref Datum e, /* const */ ref Datum d, /* const */ ref Datum p, /* const */ ref Datum q, /* const */ ref Datum u);
+         public int export_raw (/* const */ ref Datum m, /* const */ ref Datum e, /* const */ ref Datum d, /* const */ ref Datum p, /* const */ ref Datum q, /* const */ ref Datum u, out uint bits);
+         public int import_pkcs1 (/* const */ ref Datum pkcs1_params, X509.CertificateFormat format);
+         public int export_pkcs1 (X509.CertificateFormat format, void* params_data, ref size_t params_data_size);
+ 
+         public int generate2 (uint bits);
+     }
+ 
+     [Compact]
+     [CCode (cname = "struct gnutls_priority_st", free_function = "gnutls_priority_deinit")]
+     public class Priority {
+         private static int init (out Priority self, string priority, out char* err_pos);
+         public static Priority create (string priority, out ErrorCode err = null, out char* err_pos = null)
+         {
+             Priority result;
+             var ret = init (out result, priority, out err_pos);
+             if (&err != null) {
+                 err = (ErrorCode) ret;
+             } else {
+                 err = 0;
+             }
+             return result;
+         }
+     }
+ 
+     [SimpleType]
+     [CCode (cname = "gnutls_datum_t", has_type_id = false)]
+     public struct Datum {
+         public void* data;
+         public uint size;
+     }
+ 
+     [CCode (cname = "gnutls_params_st", has_type_id = false)]
+     public struct Params {
+         public ParamsType type;
+         [CCode (cname = "params.dh")]
+         public DHParams dh_params;
+         [CCode (cname = "params.rsa_export")]
+         public RSAParams rsa_params;
+         public bool deinit;
+     }
+ 
+     [CCode (cname = "gnutls_params_function *", has_target = false)]
+     public delegate int ParamsFunction (Session session, ParamsType type, Params params);
+ 
+     [CCode (cname = "gnutls_oprfi_callback_func", instance_pos = "1.2")]
+     public delegate int OprfiCallbackFunc (Session session,
+                                            [CCode (array_length_pos = "1.8", array_length_type = "size_t")] /* const */ uint8[] in_oprfi,
+                                            [CCode (array_length_pos = "1.8", array_length_type = "size_t")] uint8[] out_oprfi);
+ 
+     /* Supplemental data, RFC 4680. */
+     [CCode (cname = "gnutls_supplemental_data_format_type_t", has_type_id = false)]
+     public enum SupplementalDataFormatType {
+         USER_MAPPING_DATA;
+ 
+         [CCode (cname = "gnutls_supplemental_get_name")]
+         public unowned string? get_name ();
+     }
+ 
+     [CCode (cname = "TLS_MASTER_SIZE")]
+     public const int TLS_MASTER_SIZE;
+     [CCode (cname = "TLS_RANDOM_SIZE")]
+     public const int TLS_RANDOM_SIZE;
+ 
+     [CCode (cname = "gnutls_db_store_func", has_target = false)]
+     public delegate int DBStoreFunc (void* ptr, Datum key, Datum data);
+     [CCode (cname = "gnutls_db_remove_func", has_target = false)]
+     public delegate int DBRemoveFunc (void* ptr, Datum key);
+     [CCode (cname = "gnutls_db_retr_func", has_target = false)]
+     public delegate Datum DBRetrieveFunc (void* ptr, Datum key);
+ 
+     [CCode (cname = "gnutls_handshake_post_client_hello_func", has_target = false)]
+     public delegate int HandshakePostClientHelloFunc (Session session);
+ 
+     // External signing callback.  Experimental.
+     [CCode (cname = "gnutls_sign_func", instance_pos = "1.9")]
+     public delegate int SignFunc (Session session, CertificateType cert_type, /* const */ ref Datum cert, /* const */ ref Datum hash, out Datum signature);
+ 
+     [CCode (cname = "gnutls_pull_func", has_target = false)]
+     public delegate ssize_t PullFunc (void* transport_ptr, void* buffer, size_t count);
+     [CCode (cname = "gnutls_push_func", has_target = false)]
+     public delegate ssize_t PushFunc (void* transport_ptr, void* buffer, size_t count);
+ 
+     [Compact]
+     [CCode (cname = "struct gnutls_session_int", free_function = "gnutls_deinit")]
+     public class Session {
+         [CCode (cname = "gnutls_init")]
+         private static int init (out Session session, int con_end);
+         protected static Session? create (int con_end)
+         {
+             Session result;
+             var ret = init (out result, con_end);
+             if (ret != 0)
+                 GLib.error ("%s", ((ErrorCode)ret).to_string ());
+             return result;
+         }
+ 
+         [CCode (cname = "gnutls_credentials_set")]
+         public int set_credentials (CredentialsType type, void* cred);
+         [CCode (cname = "gnutls_credentials_clear")]
+         public void clear_credentials ();
+ 
+         [CCode (cname = "gnutls_handshake")]
+         public int handshake ();
+         [CCode (cname = "gnutls_bye")]
+         public int bye (CloseRequest how);
+ 
+         [CCode (cname = "gnutls_session_is_resumed")]
+         public bool is_resumed ();
+ 
+         [CCode (cname = "gnutls_alert_get")]
+         public AlertDescription get_last_alert ();
+         [CCode (cname = "gnutls_alert_send")]
+         public int send_alert (AlertLevel level, AlertDescription desc);
+         [CCode (cname = "gnutls_alert_send_appropriate")]
+         public int send_appropriate_alert (ErrorCode err);
+ 
+         [CCode (cname = "gnutls_cipher_get")]
+         public CipherAlgorithm get_cipher ();
+         [CCode (cname = "gnutls_kx_get")]
+         public KXAlgorithm get_kx ();
+         [CCode (cname = "gnutls_mac_get")]
+         public MacAlgorithm get_mac ();
+         [CCode (cname = "gnutls_compression_get")]
+         public CompressionMethod get_compression ();
+         [CCode (cname = "gnutls_certificate_type_get")]
+         public CertificateType get_certificate_type ();
+         [CCode (cname = "gnutls_protocol_get_version")]
+         public Protocol get_protocol_version ();
+         [CCode (cname = "gnutls_record_get_max_size")]
+         public size_t get_max_record_size ();
+         [CCode (cname = "gnutls_dh_get_prime_bits")]
+         public int get_dh_prime_bits ();
+         [CCode (cname = "gnutls_dh_get_secret_bits")]
+         public int get_dh_secret_bits ();
+         [CCode (cname = "gnutls_dh_get_peers_public_bits")]
+         public int get_peers_dh_public_bits ();
+         [CCode (cname = "gnutls_dh_get_group")]
+         public int get_dh_group (out Datum raw_gen, out Datum raw_prime);
+         [CCode (cname = "gnutls_dh_get_pubkey")]
+         public int get_dh_pubkey (out Datum raw_key);
+         [CCode (cname = "gnutls_rsa_export_get_pubkey")]
+         public int get_rsa_export_pubkey (out Datum exponent, out Datum modulus);
+         [CCode (cname = "gnutls_rsa_export_get_modulus_bits")]
+         public int get_rsa_export_modulus_bits ();
+ 
+         [CCode (cname = "gnutls_handshake_set_private_extensions")]
+         public void allow_private_extensions (bool allow);
+         [CCode (cname = "gnutls_handshake_get_last_out")]
+         public HandshakeDescription get_last_out_handshake ();
+         [CCode (cname = "gnutls_handshake_get_last_in")]
+         public HandshakeDescription get_last_in_handshake ();
+ 
+         [CCode (cname = "gnutls_record_send")]
+         public ssize_t send (void* buffer, size_t count);
+         [CCode (cname = "gnutls_record_recv")]
+         public ssize_t receive (void* buffer, size_t count);
+ 
+         [CCode (cname = "gnutls_record_get_direction")]
+         public int get_last_direction ();
+ 
+         [CCode (cname = "gnutls_record_check_pending")]
+         public size_t check_pending ();
+ 
+         [CCode (cname = "gnutls_cipher_set_priority")]
+         public int set_cipher_priority ([CCode (array_length = "false", array_null_terminated = "true")] CipherAlgorithm[] list);
+         [CCode (cname = "gnutls_mac_set_priority")]
+         public int set_mac_priority ([CCode (array_length = "false", array_null_terminated = "true")] MacAlgorithm[] list);
+         [CCode (cname = "gnutls_compression_set_priority")]
+         public int set_compression_priority ([CCode (array_length = "false", array_null_terminated = "true")] CompressionMethod[] list);
+         [CCode (cname = "gnutls_kx_set_priority")]
+         public int set_kx_priority ([CCode (array_length = "false", array_null_terminated = "true")] KXAlgorithm[] list);
+         [CCode (cname = "gnutls_protocol_set_priority")]
+         public int set_protocol_priority ([CCode (array_length = "false", array_null_terminated = "true")] Protocol[] list);
+         [CCode (cname = "gnutls_certificate_type_set_priority")]
+         public int set_certificate_type_priority ([CCode (array_length = "false", array_null_terminated = "true")] CertificateType[] list);
+ 
+         [CCode (cname = "gnutls_priority_set")]
+         public int set_priority (Priority priority);
+         [CCode (cname = "gnutls_priority_set_direct")]
+         public int set_priority_from_string (string priority, out unowned string err_pos = null);
+         [CCode (cname = "gnutls_set_default_priority")]
+         public int set_default_priority ();
+         [CCode (cname = "gnutls_set_default_export_priority")]
+         public int set_default_export_priority ();
+ 
+         [CCode (cname = "GNUTLS_MAX_SESSION_ID")]
+         public const int MAX_SESSION_ID;
+ 
+         [CCode (cname = "gnutls_session_get_id")]
+         public int get_id (void* session_id, ref size_t session_id_size);
+ 
+         [CCode (cname = "gnutls_session_get_server_random")]
+         public void* get_server_random ();
+         [CCode (cname = "gnutls_session_get_client_random")]
+         public void* get_client_random ();
+         [CCode (cname = "gnutls_session_get_master_secret")]
+         public void* get_master_secret ();
+ 
+         [CCode (cname = "gnutls_transport_set_ptr")]
+         public void set_transport_ptr (void* ptr);
+         [CCode (cname = "gnutls_transport_set_ptr2")]
+         public void set_transport_ptr2 (void* recv_ptr, void* send_ptr);
+         [CCode (cname = "gnutls_transport_set_lowat")]
+         public void set_lowat (int num);
+         [CCode (cname = "gnutls_transport_set_push_function")]
+         public void set_push_function (PushFunc func);
+         [CCode (cname = "gnutls_transport_set_pull_function")]
+         public void set_pull_function (PullFunc func);
+ 
+         [CCode (cname = "gnutls_transport_set_errno")]
+         public void set_errno (int err);
+ 
+         [CCode (cname = "gnutls_session_set_ptr")]
+         public void set_ptr (void* ptr);
+         [CCode (cname = "gnutls_session_get_ptr")]
+         public void* get_ptr ();
+ 
+         [CCode (cname = "gnutls_auth_get_type")]
+         public CredentialsType get_auth_type ();
+     //	[CCode (cname = "gnutls_auth_server_get_type")]
+     //	public CredentialsType get_server_auth_type ();
+     //	[CCode (cname = "gnutls_auth_client_get_type")]
+     //	public CredentialsType get_client_auth_type ();
+ 
+         [CCode (cname = "gnutls_sign_callback_set")]
+         public void set_sign_callback (SignFunc func);
+         [CCode (cname = "gnutls_sign_callback_get")]
+         public SignFunc get_sign_callback ();
+ 
+         [CCode (cname = "gnutls_certificate_get_peers", array_length_type = "unsigned int")]
+         public unowned Datum[]? get_peer_certificates ();
+         [CCode (cname = "gnutls_certificate_get_ours")]
+         public unowned Datum? get_our_certificate ();
+ 
+         [CCode (cname = "gnutls_certificate_verify_peers2")]
+         public int verify_peer_certificate (out CertificateStatus status);
+     }
+ 
+     [CCode (cname = "struct gnutls_session_int", lower_case_cprefix = "gnutls_", free_function = "gnutls_deinit")]
+     public class ClientSession: Session {
+ 
+         public static ClientSession create ()
+         {
+             return (ClientSession) Session.create (2);
+         }
+ 
+         [CCode (cname = "gnutls_record_set_max_size")]
+         public ssize_t set_max_record_size (size_t size);
+ 
+         [CCode (cname = "gnutls_dh_set_prime_bits")]
+         public void set_dh_prime_bits (uint bits);
+ 
+         [CCode (cname = "gnutls_server_name_get")]
+         public int get_server_name (void* data, out size_t data_length, out ServerNameType type, uint index);
+ 
+         [CCode (cname = "gnutls_oprfi_enable_client")]
+         public void enable_oprfi ([CCode (array_length_pos = "0.9", array_length_type = "size_t")] uint8[] data);
+ 
+         [CCode (cname = "gnutls_session_set_data")]
+         public int set_session_data (void* session_data, size_t session_data_size);
+         [CCode (cname = "gnutls_session_get_data")]
+         public int get_session_data (void* session_data, out size_t session_data_size);
+         [CCode (cname = "gnutls_session_get_data2")]
+         public int get_session_data2 (out Datum data);
+ 
+         [CCode (cname = "gnutls_openpgp_send_cert")]
+         public void set_openpgp_send_cert (bool fingerprint_only);
+ 
+         [CCode (cname = "gnutls_psk_client_get_hint")]
+         public unowned string get_psk_hint ();
+ 
+         [CCode (cname = "gnutls_certificate_client_get_request_status")]
+         public int get_certificate_request_status ();
+     }
+ 
+     [CCode (cname = "struct gnutls_session_int", lower_case_cprefix = "gnutls_", free_function = "gnutls_deinit")]
+     public class ServerSession: Session {
+ 
+         public static ServerSession create ()
+         {
+             return (ServerSession) Session.create (1);
+         }
+ 
+         public int rehandshake ();
+ 
+         [CCode (cname = "gnutls_session_enable_compatibility_mode")]
+         public void enable_compatibility_mode ();
+ 
+         [CCode (cname = "gnutls_record_disable_padding")]
+         public void disable_record_padding ();
+ 
+         [CCode (cname = "gnutls_server_name_set")]
+         public int set_server_name (ServerNameType type, void* data, size_t data_length);
+ 
+         [CCode (cname = "gnutls_oprfi_enable_server")]
+         public void enable_oprfi (OprfiCallbackFunc cb);
+ 
+         public void db_set_cache_expiration (int seconds);
+         public void db_remove_session ();
+         public void db_set_retrieve_function (DBRetrieveFunc func);
+         public void db_set_remove_function (DBRemoveFunc func);
+         public void db_set_store_function (DBStoreFunc func);
+         public void db_set_ptr (void* ptr);
+         public void* db_get_ptr ();
+         public int db_check_entry (Datum session_entry);
+ 
+         [CCode (cname = "gnutls_handshake_set_post_client_hello_function")]
+         public void set_post_client_hello_function (HandshakePostClientHelloFunc func);
+ 
+         [CCode (cname = "gnutls_handshake_set_max_packet_length")]
+         public void set_max_handshake_packet_length (size_t max);
+ 
+         [CCode (cname = "gnutls_certificate_server_set_request")]
+         public void set_certificate_request (CertificateRequest req);
+ 
+         [CCode (cname = "gnutls_certificate_send_x509_rdn_sequence")]
+         public void disable_sending_x509_rdn_sequence (bool disable);
+ 
+         [CCode (cname = "gnutls_psk_server_get_username")]
+         public unowned string get_psk_username ();
+ 
+         [CCode (cheader_filename = "gnutls/openpgp.h", cname = "gnutls_openpgp_set_recv_key_function")]
+         public void set_openpgp_recv_key_function (OpenPGP.RecvKeyFunc func);
+     }
+ 
+ 
+     [Compact]
+     [CCode (cname = "struct gnutls_anon_server_credentials_st", free_function = "gnutls_anon_free_server_credentials")]
+     public class AnonServerCredentials
+     {
+         [CCode (cname = "gnutls_anon_allocate_server_credentials")]
+         private static int allocate (out AnonServerCredentials credentials);
+         public static AnonServerCredentials create ()
+         {
+             AnonServerCredentials result;
+             var ret = allocate (out result);
+             if (ret != 0)
+                 GLib.error ("%s", ((ErrorCode)ret).to_string ());
+             return result;
+         }
+ 
+ 
+         [CCode (cname = "gnutls_anon_set_server_dh_params")]
+         public void set_dh_params (DHParams dh_params);
+ 
+     //	[CCode (cname = "gnutls_anon_set_server_params_function")]
+     //	public void set_server_params_function (ParamsFunction func);
+ 
+         [CCode (cname = "gnutls_anon_set_params_function")]
+         public void set_params_function (ParamsFunction func);
+     }
+ 
+     [Compact]
+     [CCode (cname = "struct gnutls_anon_client_credentials_st", free_function = "gnutls_anon_free_client_credentials")]
+     public class AnonClientCredentials
+     {
+         [CCode (cname = "gnutls_anon_allocate_client_credentials")]
+         private static int allocate (out AnonClientCredentials credentials);
+         public static AnonClientCredentials create ()
+         {
+             AnonClientCredentials result;
+             var ret = allocate (out result);
+             if (ret != 0)
+                 GLib.error ("%s", ((ErrorCode)ret).to_string ());
+             return result;
+         }
+     }
+ 
+     [CCode (cheader_filename = "gnutls/x509.h", cprefix = "GNUTLS_")]
+     namespace X509
+     {
+         // Some OIDs usually found in Distinguished names, or
+         // in Subject Directory Attribute extensions.
+ 
+         public const string OID_X520_COUNTRY_NAME;
+         public const string OID_X520_ORGANIZATION_NAME;
+         public const string OID_X520_ORGANIZATIONAL_UNIT_NAME;
+         public const string OID_X520_COMMON_NAME;
+         public const string OID_X520_LOCALITY_NAME;
+         public const string OID_X520_STATE_OR_PROVINCE_NAME;
+ 
+         public const string OID_X520_INITIALS;
+         public const string OID_X520_GENERATION_QUALIFIER;
+         public const string OID_X520_SURNAME;
+         public const string OID_X520_GIVEN_NAME;
+         public const string OID_X520_TITLE;
+         public const string OID_X520_DN_QUALIFIER;
+         public const string OID_X520_PSEUDONYM;
+ 
+         public const string OID_LDAP_DC;
+         public const string OID_LDAP_UID;
+ 
+         // The following should not be included in DN.
+ 
+         public const string OID_PKCS9_EMAIL;
+ 
+         public const string OID_PKIX_DATE_OF_BIRTH;
+         public const string OID_PKIX_PLACE_OF_BIRTH;
+         public const string OID_PKIX_GENDER;
+         public const string OID_PKIX_COUNTRY_OF_CITIZENSHIP;
+         public const string OID_PKIX_COUNTRY_OF_RESIDENCE;
+ 
+         // Key purpose Object Identifiers.
+ 
+         public const string KP_TLS_WWW_SERVER;
+         public const string KP_TLS_WWW_CLIENT;
+         public const string KP_CODE_SIGNING;
+         public const string KP_EMAIL_PROTECTION;
+         public const string KP_TIME_STAMPING;
+         public const string KP_OCSP_SIGNING;
+         public const string KP_ANY;
+ 
+ 
+         [CCode (cname = "gnutls_x509_crt_fmt_t", cprefix = "GNUTLS_X509_FMT_", has_type_id = false)]
+         public enum CertificateFormat {
+             DER,
+             PEM
+         }
+ 
+         [Flags]
+         [CCode (cname = "gnutls_certificate_import_flags", cprefix = "GNUTLS_X509_CRT_", has_type_id = false)]
+         public enum CertificateImportFlags {
+             /* Fail if the certificates in the buffer are more than the space
+             * allocated for certificates. The error code will be
+             * GNUTLS_E_SHORT_MEMORY_BUFFER.
+             */
+             LIST_IMPORT_FAIL_IF_EXCEED    // == 1
+         }
+ 
+         [Flags]
+         [CCode (cname = "unsigned int", cprefix = "GNUTLS_CRL_REASON_", has_type_id = false)]
+         public enum RevocationReasons {
+             UNUSED,
+             KEY_COMPROMISE,
+             CA_COMPROMISE,
+             AFFILIATION_CHANGED,
+             SUPERSEEDED,
+             CESSATION_OF_OPERATION,
+             CERTIFICATE_HOLD,
+             PRIVILEGE_WITHDRAWN,
+             AA_COMPROMISE
+         }
+ 
+         [Flags]
+         [CCode (cname = "gnutls_certificate_verify_flags", cprefix = "GNUTLS_VERIFY_", has_type_id = false)]
+         public enum CertificateVerifyFlags
+         {
+             // If set a signer does not have to be a certificate authority. This
+             // flag should normaly be disabled, unless you know what this means.
+             DISABLE_CA_SIGN,
+ 
+             // Allow only trusted CA certificates that have version 1.  This is
+             // safer than GNUTLS_VERIFY_ALLOW_ANY_X509_V1_CA_CRT, and should be
+             // used instead. That way only signers in your trusted list will be
+             // allowed to have certificates of version 1.
+             ALLOW_X509_V1_CA_CRT,
+ 
+             // If a certificate is not signed by anyone trusted but exists in
+             // the trusted CA list do not treat it as trusted.
+             DO_NOT_ALLOW_SAME,
+ 
+             // Allow CA certificates that have version 1 (both root and
+             // intermediate). This might be dangerous since those haven't the
+             // basicConstraints extension. Must be used in combination with
+             // GNUTLS_VERIFY_ALLOW_X509_V1_CA_CRT.
+             ALLOW_ANY_X509_V1_CA_CRT,
+ 
+             // Allow certificates to be signed using the broken MD2 algorithm.
+             ALLOW_SIGN_RSA_MD2,
+ 
+             // Allow certificates to be signed using the broken MD5 algorithm.
+             ALLOW_SIGN_RSA_MD5
+         }
+ 
+         [CCode (cname = "gnutls_x509_subject_alt_name_t", has_type_id = false)]
+         public enum SubjectAltName {
+             DNSNAME,
+             RFC822NAME,
+             URI,
+             IPADDRESS,
+             OTHERNAME,
+             DN,
+ 
+             OTHERNAME_XMPP
+         }
+ 
+         [Compact]
+         [CCode (cname = "void", cprefix = "gnutls_x509_dn_", free_function = "gnutls_x509_dn_deinit")]
+         public class DN
+         {
+             private static int init (out DN dn);
+             public static DN create ()
+             {
+                 DN result;
+                 var ret = init (out result);
+                 if (ret != 0)
+                     GLib.error ("%s", ((ErrorCode)ret).to_string ());
+                 return result;
+             }
+ 
+             public int get_rdn_ava (int irdn, int iava, out unowned Ava ava);
+ 
+             public int import (ref Datum data);
+             public int export (CertificateFormat format, void* output, ref size_t output_size);
+ 
+         }
+ 
+         // RDN handling.
+         public int rdn_get (ref Datum idn, char* buf, ref size_t buf_size);
+         public int rdn_get_oid (ref Datum idn, int index, void* buf, ref size_t buf_size);
+         public int rdn_get_by_oid (ref Datum idn, string oid, int index, uint raw_flag, void* buf, ref size_t buf_size);
+ 
+         [SimpleType]
+         [CCode (cname = "gnutls_x509_ava_st", has_type_id = false)]
+         public struct Ava
+         {
+             [CCode (cname = "oid.data", array_length_cname = "oid.size")]
+             unowned uint8[] oid;
+             [CCode (cname = "value.data", array_length_cname = "value.size")]
+             unowned uint8[] value;
+             ulong value_tag;
+         }
+ 
+         [Compact]
+         [CCode (cname = "struct gnutls_x509_crt_int", cprefix = "gnutls_x509_crt_", free_function = "gnutls_x509_crt_deinit")]
+         public class Certificate
+         {
+             private static int init (out Certificate cert);
+             public static Certificate create ()
+             {
+                 Certificate result;
+                 var ret = init (out result);
+                 if (ret != 0)
+                     GLib.error ("%s", ((ErrorCode)ret).to_string ());
+                 return result;
+             }
+ 
+             public int import (ref Datum data, CertificateFormat format);
+             public int export (CertificateFormat format, void* output, ref size_t output_size);
+ 
+             public static int list_import ([CCode (array_length = "false")] Certificate[]? certs,
+                                            ref uint cert_max, ref Datum data,
+                                            CertificateFormat format, bool fail_if_exceed);
+ 
+ 
+ 
+             public int get_issuer_dn (char* buf, ref size_t buf_size);
+             public int get_issuer_dn_oid (int index, void* oid, ref size_t oid_size);
+             public int get_issuer_dn_by_oid (string oid, int index, uint raw_flag, void* buf, ref size_t buf_size);
+ 
+             public int get_dn (char* buf, ref size_t buf_size);
+             public int get_dn_oid (int index, void* oid, ref size_t oid_size);
+             public int get_dn_by_oid (string oid, int index, uint raw_flag, void* buf, ref size_t buf_size);
+ 
+ 
+             public int get_subject (out DN dn);
+             public int get_issuer (out DN dn);
+ 
+             public bool check_hostname (string hostname);
+ 
+             public SignAlgorithm get_signature_algorithm ();
+ 
+             public int get_signature (char* sig, ref size_t sig_size);
+ 
+             public int get_version ();
+ 
+             public int get_key_id (uint flags, uchar* output, ref size_t output_size);
+ 
+             public int set_authority_key_id (void* id, size_t id_size);
+             public int get_authority_key_id (void* ret, ref size_t ret_size, out bool critical);
+ 
+             public int get_subject_key_id (void* ret, ref size_t ret_size, out bool critical);
+ 
+             public int get_crl_dist_points (uint seq, void* ret, ref size_t ret_size, out RevocationReasons reason_flags, out bool critical);
+             public int set_crl_dist_points (SubjectAltName type, void* data_string, RevocationReasons reason_flags);
+             public int cpy_crl_dist_points (Certificate source);
+ 
+             public time_t get_activation_time ();
+             public time_t get_expiration_time ();
+ 
+             public int get_serial (void* result, ref size_t result_size);
+ 
+             public PKAlgorithm get_pk_algorithm (out uint bits);
+             public int get_pk_rsa_raw (out Datum modulus, out Datum exponent);
+             public int get_pk_dsa_raw (out Datum p, out Datum q, out Datum g, out Datum y);
+ 
+             public int get_subject_alt_name (uint seq, void* ret, ref size_t ret_size, out bool critical);
+             public int get_subject_alt_name2 (uint seq, void* ret, ref size_t ret_size, out SubjectAltName ret_type, out bool critical);
+ 
+             public int get_subject_alt_othername_oid (uint seq, void* ret, ref size_t ret_size);
+ 
+             public int get_ca_status (out bool critical);
+ 
+             public int get_basic_constraints (out bool critical, out int ca, out int pathlen);
+ 
+             public int get_key_usage (out KeyUsage key_usage, out bool critical);
+             public int set_key_usage (KeyUsage usage);
+ 
+             public int get_proxy (out bool critical, out int pathlen, [CCode (array_length = "false")] out char[] policyLanguage, out char[] policy);
+ 
+             public bool dn_oid_known (string oid);
+ 
+             public int get_extension_oid (int index, void* oid, ref size_t oid_size);
+             public int get_extension_by_oid (string oid, int index, void* buf, ref size_t buf_size, out bool critical);
+ 
+             public int get_extension_info (int index, void* oid, ref size_t oid_size, out bool critical);
+             public int get_extension_data (int index, void* data, ref size_t data_size);
+ 
+             public int set_extension_by_oid (string oid, void* buf, size_t buf_size, bool critical);
+             public int set_dn_by_oid (string oid, uint raw_flag, void* name, uint name_size);
+             public int set_issuer_dn_by_oid (string oid, uint raw_flag, void* name, uint name_size);
+             public int set_version (uint version);
+             public int set_key (PrivateKey key);
+             public int set_ca_status (uint ca);
+             public int set_basic_constraints (uint ca, int pathLenConstraint);
+             public int set_subject_alternative_name (SubjectAltName type, string data_string);
+ 
+             public int sign (Certificate issuer, PrivateKey issuer_key);
+             public int sign2 (Certificate issuer, PrivateKey issuer_key, DigestAlgorithm alg, uint flags);
+ 
+             public int set_activation_time (time_t act_time);
+             public int set_expiration_time (time_t exp_time);
+             public int set_serial (void* serial, size_t serial_size);
+ 
+             public int set_subject_key_id (void* id, size_t id_size);
+             public int set_proxy_dn (Certificate eecrt, uint raw_flag, void* name, uint name_size);
+             public int set_proxy (int pathLenConstraint, string policyLanguage, [CCode (array_length_type = "size_t")] uint8[] policy);
+ 
+             public int print (CertificatePrintFormats format, out Datum output);
+ 
+             public int get_raw_issuer_dn (out unowned Datum start);
+             public int get_raw_dn (out unowned Datum start);
+ 
+             public int verify_data2 (SignAlgorithm algo, uint flags, ref Datum data, ref Datum signature);
+ 
+             private int set_crq (CertificateRequest crq);
+ 
+             // verification
+ 
+             public int check_issuer (Certificate issuer);
+             public static int list_verify (Certificate[] cert_list, Certificate[] CA_list, Certificate[] CLR_list, CertificateVerifyFlags flags, out CertificateStatus verify);
+             public int verify (Certificate[] CA_list, CertificateVerifyFlags flags, out CertificateStatus verify);
+             public int check_revocation (CRL[] crl_list);
+             public int get_fingerprint (DigestAlgorithm algo, void* buf, ref size_t buf_size);
+             public int get_key_purpose_oid (int index, void* oid, ref size_t oid_size, out bool critical);
+             public int set_key_purpose_oid (string oid, bool critical);
+         }
+ 
+         [Compact]
+         [CCode (cname = "struct gnutls_x509_crl_int", free_function = "gnutls_x509_crl_deinit", cprefix = "gnutls_x509_crl_")]
+         public class CRL
+         {
+             private static int init (out CRL crl);
+             public static CRL create ()
+             {
+                 CRL result;
+                 var ret = init (out result);
+                 if (ret != 0)
+                     GLib.error ("%s", ((ErrorCode)ret).to_string ());
+                 return result;
+             }
+ 
+             public int import (ref Datum data, CertificateFormat format);
+             public int export (CertificateFormat format, void* output, ref size_t output_size);
+ 
+             public int get_issuer_dn (char* buf, ref size_t buf_size);
+             public int get_issuer_dn_by_oid (string oid, int index, uint raw_flag, void* buf, ref size_t buf_size);
+ 
+             public int get_dn_oid (int index, void* oid, ref size_t oid_size);
+ 
+             public int get_signature_algorithm ();
+             public int get_signature (char* sig, ref size_t sig_size);
+             public int get_version ();
+ 
+             public time_t get_this_update ();
+             public time_t get_next_update ();
+ 
+             public int get_crt_count ();
+             public int get_crt_serial (int index, uchar* serial, ref size_t serial_size, out time_t t);
+ 
+             // aliases for previous two
+             public int get_certificate_count ();
+             public int get_certificate (int index, uchar* serial, ref size_t serial_size, out time_t t);
+ 
+             public int check_issuer (Certificate issuer);
+ 
+             public int verify (Certificate[] ca_list, CertificateVerifyFlags flags, out CertificateStatus verify);
+ 
+             // CRL writing
+ 
+             public int set_version (uint version);
+             public int sign (Certificate issuer, PrivateKey issuer_key);
+             public int sign2 (Certificate issuer, PrivateKey issuer_key, DigestAlgorithm algo, uint flags);
+ 
+             public int set_this_update (time_t act_time);
+             public int set_next_update (time_t exp_time);
+ 
+             public int set_crt_serial (void* serial, size_t serial_size, time_t revocation_time);
+             public int set_crt (Certificate crt, time_t revocation_time);
+ 
+             public int print (CertificatePrintFormats format, out Datum output);
+         }
+ 
+         [Compact]
+         [CCode (cname = "struct gnutls_pkcs7_int", cprefix = "gnutls_pkcs7_", free_function = "gnutls_pkcs7_deinit")]
+         public class PKCS7
+         {
+             private static int init (out PKCS7 pkcs7);
+             public static PKCS7 create ()
+             {
+                 PKCS7 result;
+                 var ret = init (out result);
+                 if (ret != 0)
+                     GLib.error ("%s", ((ErrorCode)ret).to_string ());
+                 return result;
+             }
+ 
+             public int import (ref Datum data, CertificateFormat format);
+             public int export (CertificateFormat format, void* output, ref size_t output_size);
+ 
+             public int get_crt_count ();
+             public int get_crt_raw (int index, void* certificate, ref size_t certificate_size);
+             public int set_crt_raw (ref Datum crt);
+             public int set_crt (Certificate crt);
+             public int delete_crt (int index);
+ 
+             public int get_crl_count ();
+             public int get_crl_raw (int index, void* crl, ref size_t crl_size);
+             public int set_crl_raw (ref Datum crt);
+             public int set_crl (CRL crl);
+             public int delete_crl (int index);
+         }
+ 
+         // Flags for the gnutls_x509_privkey_export_pkcs8() function.
+         [Flags]
+         [CCode (cname = "gnutls_pkcs_encrypt_flags_t", cprefix = "GNUTLS_PKCS_", has_type_id = false)]
+         public enum PKCSEncryptFlags {
+             PLAIN,
+             USE_PKCS12_3DES,
+             USE_PKCS12_ARCFOUR,
+             USE_PKCS12_RC2_40,
+             USE_PBES2_3DES
+         }
+ 
+         [Compact]
+         [CCode (cname = "struct gnutls_x509_privkey_int", cprefix = "gnutls_x509_privkey_", free_function = "gnutls_x509_privkey_deinit")]
+         public class PrivateKey
+         {
+             private static int init (out PrivateKey key);
+             public static PrivateKey create ()
+             {
+                 PrivateKey result;
+                 var ret = init (out result);
+                 if (ret != 0)
+                     GLib.error ("%s", ((ErrorCode)ret).to_string ());
+                 return result;
+             }
+ 
+             public int cpy (PrivateKey source);
+ 
+             public int import (ref Datum data, CertificateFormat format);
+             public int import_pkcs8 (ref Datum data, CertificateFormat format, string? password, PKCSEncryptFlags flags);
+             public int import_rsa_raw (ref Datum m, ref Datum e, ref Datum d, ref Datum p, ref Datum q, ref Datum u);
+             public int import_dsa_raw (ref Datum p, ref Datum q, ref Datum g, ref Datum y, ref Datum x);
+ 
+             public int export (CertificateFormat format, void* output, ref size_t output_size);
+             public int export_pkcs8 (CertificateFormat format, string password, PKCSEncryptFlags flags, void* output, ref size_t output_size);
+             public int export_rsa_raw (out Datum m, out Datum e, out Datum d, out Datum p, out Datum q, out Datum u);
+             public int export_dsa_raw (out Datum p, out Datum q, out Datum g, out Datum y, out Datum x);
+ 
+             public int fix ();
+             public int generate (PKAlgorithm algo, uint bits, uint flags = 0);
+ 
+             public int get_pk_algorithm ();
+             public int get_key_id (uint flags, uchar* output, ref size_t output_size);
+ 
+             // Signing stuff
+ 
+             public int sign_data (DigestAlgorithm digest, uint flags, ref Datum data, void* signature, ref size_t signature_size);
+             public int verify_data (uint flags, ref Datum data, ref Datum signature);
+             public int sign_hash (ref Datum hash, out Datum signature);
+         }
+ 
+         [Compact]
+         [CCode (cname = "struct gnutls_x509_crq_int", cprefix = "gnutls_x509_crq_", free_function = "gnutls_x509_crq_deinit")]
+         public class CertificateRequest
+         {
+             private static int init (out CertificateRequest request);
+             public static CertificateRequest create ()
+             {
+                 CertificateRequest result;
+                 var ret = init (out result);
+                 if (ret != 0)
+                     GLib.error ("%s", ((ErrorCode)ret).to_string ());
+                 return result;
+             }
+ 
+             public int import (ref Datum data, CertificateFormat format);
+             public int export (CertificateFormat format, void* output, ref size_t output_size);
+ 
+             public int get_pk_algorithm (out uint bits);
+             public int get_dn (char* buf, ref size_t buf_size);
+             public int get_dn_oid (int index, void* oid, ref size_t oid_size);
+             public int get_dn_by_oid (string oid, int index, uint raw_flag, void* buf, ref size_t buf_size);
+             public int set_dn_by_oid (string oid, uint raw_flag, void* name, uint name_size);
+ 
+             public int set_version (uint version);
+ 
+             public int set_key (PrivateKey key);
+ 
+             public int sign (PrivateKey key);
+             public int sign2 (PrivateKey key, DigestAlgorithm algo, uint flags);
+ 
+             public int set_challenge_password (string pass);
+             public int get_challenge_password (char* pass, ref size_t pass_size);
+ 
+             public int set_attribute_by_oid (string oid, void* buf, size_t buf_size);
+             public int get_attribute_by_oid (string oid, int index, void* buf, ref size_t buf_size);
+         }
+ 
+         [Compact]
+         [CCode (cheader_filename = "gnutls/pkcs12.h", cname = "struct gnutls_pkcs12_int", cprefix = "gnutls_pkcs12_", free_function = "gnutls_pkcs12_deinit")]
+         public class PKCS12
+         {
+             private static int init (out PKCS12 request);
+             public static PKCS12 create ()
+             {
+                 PKCS12 result;
+                 var ret = init (out result);
+                 if (ret != 0)
+                     GLib.error ("%s", ((ErrorCode)ret).to_string ());
+                 return result;
+             }
+ 
+             public int import (ref Datum data, CertificateFormat format, uint flags);
+             public int export (CertificateFormat format, void* output, ref size_t output_size);
+ 
+             public int get_bag (int index, PKCS12Bag bag);
+             public int set_bag (PKCS12Bag bag);
+ 
+             public int generate_mac (string pass);
+             public int verify_mac (string pass);
+         }
+ 
+         [CCode (cheader_filename = "gnutls/pkcs12.h", cname = "gnutls_pkcs12_bag_type_t", cprefix = "GNUTLS_BAG_", has_type_id = false)]
+         public enum PKCS12BagType {
+             EMPTY,
+             PKCS8_ENCRYPTED_KEY,
+             PKCS8_KEY,
+             CERTIFICATE,
+             CRL,
+             ENCRYPTED,
+             UNKNOWN
+         }
+ 
+         [Compact]
+         [CCode (cheader_filename = "gnutls/pkcs12.h", cname = "struct gnutls_pkcs12_bag_int", cprefix = "gnutls_pkcs12_bag_", free_function = "gnutls_pkcs12_bag_deinit")]
+         public class PKCS12Bag {
+             private static int init (out PKCS12Bag request);
+             public static PKCS12Bag create ()
+             {
+                 PKCS12Bag result;
+                 var ret = init (out result);
+                 if (ret != 0)
+                     GLib.error ("%s", ((ErrorCode)ret).to_string ());
+                 return result;
+             }
+ 
+             public int decrypt (string pass);
+             public int encrypt (string pass, PKCSEncryptFlags flags);
+ 
+             public PKCS12BagType get_type (int index);
+             public int get_data (int index, out Datum data);
+             public int set_data (PKCS12BagType type, ref Datum data);
+             public int set_crl (CRL crl);
+             public int set_crt (Certificate crt);
+ 
+             public int get_count ();
+ 
+             public int get_key_id (int index, out Datum id);
+             public int set_key_id (int index, ref Datum id);
+ 
+             public int get_friendly_name (int index, out unowned string name);
+             public int set_friendly_name (int index, string name);
+         }
+     }
+ 
+     [CCode (cheader_filename = "gnutls/openpgp.h")]
+     namespace OpenPGP
+     {
+         [CCode (has_target = false)]
+         public delegate int RecvKeyFunc (Session session, uint8[] keyfpr, out Datum key);
+ 
+         [CCode (cname = "gnutls_openpgp_crt_fmt_t", cprefix = "GNUTLS_OPENPGP_FMT_", has_type_id = false)]
+         public enum CertificateFormat {
+             RAW,
+             BASE64
+         }
+ 
+         [Compact]
+         [CCode (cname = "struct gnutls_openpgp_crt_int", cprefix = "gnutls_openpgp_crt_", free_function = "gnutls_openpgp_crt_deinit")]
+         public class Certificate
+         {
+             private static int init (out Certificate crt);
+             public static Certificate create ()
+             {
+                 Certificate result;
+                 var ret = init (out result);
+                 if (ret != 0)
+                     GLib.error ("%s", ((ErrorCode)ret).to_string ());
+                 return result;
+             }
+ 
+             public int import (ref Datum data, CertificateFormat format);
+             public int export (CertificateFormat format, void* output, ref size_t output_size);
+ 
+             public int print (CertificatePrintFormats format, out Datum output);
+ 
+             public int get_key_usage (out KeyUsage key_usage);
+             public int get_fingerprint (void* fpr, ref size_t fpr_size);
+             public int get_subkey_fingerprint (uint index, void* fpr, ref size_t fpr_size);
+ 
+             public int get_name (int index, char* buf, ref size_t buf_size);
+ 
+             public PKAlgorithm get_pk_algorithm (out uint bits);
+ 
+             public int get_version ();
+ 
+             public time_t get_creation_time ();
+             public time_t get_expiration_time ();
+ 
+             // keyid is 8 bytes
+             public int get_key_id (uchar* keyid);
+ 
+             public int check_hostname (string hostname);
+ 
+             public int get_revoked_status ();
+ 
+             public int get_subkey_count ();
+             public int get_subkey_idx (/*const*/ uchar* keyid);
+             public int get_subkey_revoked_status (uint idx);
+ 
+             public PKAlgorithm get_subkey_pk_algorithm (uint idx, out uint bits);
+ 
+             public time_t get_subkey_creation_time (uint idx);
+             public time_t get_subkey_expiration_time (uint idx);
+ 
+             public int get_subkey_id (uint idx, uchar* keyid);
+             public int get_subkey_usage (uint idx, out KeyUsage key_usage);
+ 
+             public int get_pk_dsa_raw (out Datum p, out Datum q, out Datum g, out Datum y);
+             public int get_pk_rsa_raw (out Datum m, out Datum e);
+ 
+             public int get_subkey_pk_dsa_raw (uint index, out Datum p, out Datum q, out Datum g, out Datum y);
+             public int get_subkey_pk_rsa_raw (uint index, out Datum m, out Datum e);
+ 
+             public int get_preferred_key_id (uchar* keyid);
+             public int set_preferred_key_id (/* const */ uchar* keyid);
+ 
+             public int verify_ring (Keyring keyring, uint flags, out CertificateStatus verify);
+             public int verify_self (uint flags, out CertificateStatus verify);
+         }
+ 
+         [Compact]
+         [CCode (cname = "struct gnutls_openpgp_privkey_int", cprefix = "gnutls_openpgp_privkey_", free_function = "gnutls_openpgp_privkey_deinit")]
+         public class PrivateKey
+         {
+             private static int init (out PrivateKey key);
+             public static PrivateKey create ()
+             {
+                 PrivateKey result = null;
+                 var ret = init (out result);
+                 if (ret != 0)
+                     GLib.error ("%s", ((ErrorCode)ret).to_string ());
+                 return result;
+             }
+ 
+             public PKAlgorithm get_pk_algorithm (out uint bits);
+ 
+             public int import (ref Datum data, CertificateFormat format, string pass, uint flags);
+             public int export (CertificateFormat format, string password, uint flags, void* output, ref size_t output_size);
+ 
+             public int sign_hash (ref Datum hash, out Datum signature);
+             public int get_fingerprint (void* fpr, ref size_t fpr_size);
+             public int get_subkey_fingerprint (uint idx, void* fpr, ref size_t fpr_size);
+ 
+             public int get_key_id (uchar* keyid);
+             public int get_subkey_count ();
+             public int get_subkey_idx (/*const*/ uchar* keyid);
+ 
+             public int get_subkey_revoked_status (uint index);
+             public int get_revoked_status ();
+ 
+             public PKAlgorithm get_subkey_pk_algorithm (uint idx, out uint bits);
+ 
+             public time_t get_subkey_expiration_time (uint idx);
+             public time_t get_subkey_creation_time (uint idx);
+ 
+             public int get_subkey_id (uint idx, uchar* keyid);
+ 
+             public int export_subkey_dsa_raw (uint idx, out Datum p, out Datum q, out Datum g, out Datum y, out Datum x);
+             public int export_subkey_rsa_raw (uint idx, out Datum m, out Datum e, out Datum d, out Datum p, out Datum q, out Datum u);
+ 
+             public int export_dsa_raw (out Datum p, out Datum q, out Datum g, out Datum y, out Datum x);
+             public int export_rsa_raw (out Datum m, out Datum e, out Datum d, out Datum p, out Datum q, out Datum u);
+ 
+             public int set_preferred_key_id (/*const*/ uchar* keyid);
+             public int get_preferred_key_id (uchar* keyid);
+ 
+             public int get_auth_subkey (uchar* keyid, uint flag);
+         }
+ 
+         [Compact]
+         [CCode (cname = "struct gnutls_openpgp_keyring_int", cprefix = "gnutls_openpgp_keyring_", free_function = "gnutls_openpgp_keyring_deinit")]
+         public class Keyring
+         {
+             private static int init (out Keyring keyring);
+             public static Keyring create ()
+             {
+                 Keyring result;
+                 var ret = init (out result);
+                 if (ret != 0)
+                     GLib.error ("%s", ((ErrorCode)ret).to_string ());
+                 return result;
+             }
+ 
+             public int import (ref Datum data, CertificateFormat format);
+             public int check_id (/*const*/ uchar* keyid, uint flags);
+ 
+             public int get_crt_count ();
+             public int get_crt (uint index, out Certificate cert);
+         }
+     }
+ 
+ 
+     [CCode (cname = "gnutls_certificate_client_retrieve_function *", has_target = false)]
+     public delegate int ClientCertificateRetrieveFunction (Session session, Datum[] req_ca_rdn, PKAlgorithm[] pk_algos, out RetrStruct st);
+     [CCode (cname = "gnutls_certificate_server_retrieve_function *", has_target = false)]
+     public delegate int ServerCertificateRetrieveFunction (Session session, out RetrStruct st);
+ 
+     [Compact]
+     [CCode (cname = "struct gnutls_certificate_credentials_st",
+             free_function = "gnutls_certificate_free_credentials",
+             cprefix = "gnutls_certificate_")]
+     public class CertificateCredentials
+     {
+         [CCode (cname = "gnutls_certificate_allocate_credentials")]
+         private static int allocate (out CertificateCredentials credentials);
+         public static CertificateCredentials create ()
+         {
+             CertificateCredentials result;
+             var ret = allocate (out result);
+             if (ret != 0)
+                 GLib.error ("%s", ((ErrorCode)ret).to_string ());
+             return result;
+         }
+ 
+         public void free_keys ();
+         public void free_cas  ();
+         public void free_ca_names ();
+         public void free_crls ();
+ 
+         public void set_dh_params (DHParams dh_params);
+         public void set_rsa_export_params (RSAParams rsa_params);
+         public void set_verify_flags (X509.CertificateVerifyFlags flags);
+         public void set_verify_limits (uint max_bits, uint max_depth);
+ 
+         public int set_x509_trust (X509.Certificate[] ca_list);
+         public int set_x509_trust_file (string cafile, X509.CertificateFormat type);
+         public int set_x509_trust_mem (/* const */ ref Datum cadata, X509.CertificateFormat type);
+ 
+         public int set_x509_crl (X509.CRL[] crl_list);
+         public int set_x509_crl_file (string crlfile, X509.CertificateFormat type);
+         public int set_x509_crl_mem (/* const */ ref Datum crldata, X509.CertificateFormat type);
+ 
+         public int set_x509_key (X509.Certificate[] cert_list, X509.PrivateKey key);
+         public int set_x509_key_file (string certfile, string keyfile, X509.CertificateFormat type);
+         public int set_x509_key_mem (/* const */ ref Datum certdata, /* const */ ref Datum keydata, X509.CertificateFormat type);
+ 
+         public int set_x509_simple_pkcs12_file (string pkcs12file, X509.CertificateFormat type, string? password = null);
+ 
+         public void get_x509_cas ([CCode (array_length_type = "unsigned int")] out unowned X509.Certificate[] x509_ca_list);
+         public void get_x509_crls ([CCode (array_length_type = "unsigned int")] out unowned X509.CRL[] x509_crl_list);
+ 
+ 
+         [CCode (cname = "gnutls_certificate_client_set_retrieve_function")]
+         public void set_client_certificate_retrieve_function (ClientCertificateRetrieveFunction func);
+         [CCode (cname = "gnutls_certificate_server_set_retrieve_function")]
+         public void set_server_certificate_retrieve_function (ServerCertificateRetrieveFunction func);
+ 
+         [CCode (cname = "gnutls_certificate_set_params_function")]
+         public void set_params_function (ParamsFunction func);
+ 
+         // OpenPGP stuff
+ 
+         public int set_openpgp_key (OpenPGP.Certificate key, OpenPGP.PrivateKey pkey);
+ 
+         public int set_openpgp_key_file (string certfile, string keyfile, OpenPGP.CertificateFormat format);
+         public int set_openpgp_key_mem (ref Datum cert, ref Datum key, OpenPGP.CertificateFormat format);
+         public int set_openpgp_key_file2 (string certfile, string keyfile, string keyid, OpenPGP.CertificateFormat format);
+         public int set_openpgp_key_mem2 (ref Datum cert, ref Datum key, string keyid, OpenPGP.CertificateFormat format);
+ 
+         public int set_openpgp_keyring_mem (uchar* data, size_t data_size, OpenPGP.CertificateFormat format);
+         public int set_openpgp_keyring_file (string file, OpenPGP.CertificateFormat format);
+ 
+         public void get_openpgp_keyring (out unowned OpenPGP.Keyring keyring);
+     }
+ 
+     [CCode (cname = "gnutls_malloc")]
+     public void* malloc (size_t size);
+     [CCode (cname = "gnutls_secure_malloc")]
+     public void* secure_malloc (size_t size);
+     [CCode (cname = "gnutls_realloc")]
+     public void* realloc (void* ptr, size_t new_size);
+     [CCode (cname = "gnutls_calloc")]
+     public void* calloc (size_t count, size_t block_size);
+     [CCode (cname = "gnutls_free")]
+     public void free (void* ptr);
+ 
+     [CCode (cname = "gnutls_free")]
+     public void free_data ([CCode (array_length = false)] owned uint[] data);
+ 
+     [CCode (cname = "gnutls_strdup")]
+     public string strdup (string str);
+ 
+     [CCode (cname = "gnutls_alloc_function", has_target = false)]
+     public delegate void* AllocFunction (size_t size);
+     [CCode (cname = "gnutls_calloc_function", has_target = false)]
+     public delegate void* CallocFunction (size_t count, size_t block_size);
+     [CCode (cname = "gnutls_is_secure_function", has_target = false)]
+     public delegate int IsSecureFunction (void* ptr);
+     [CCode (cname = "gnutls_free_function", has_target = false)]
+     public delegate void FreeFunction (void* ptr);
+     [CCode (cname = "gnutls_realloc_function", has_target = false)]
+     public delegate void* ReallocFunction (void* ptr, size_t new_size);
+ 
+     public int global_init ();
+     public void global_deinit ();
+ 
+     [CCode (cname = "gnutls_global_set_mem_functions")]
+     public void set_mem_functions (AllocFunction alloc_func, AllocFunction secure_alloc_func,
+                                    IsSecureFunction is_secure_func, ReallocFunction realloc_func,
+                                    FreeFunction free_func);
+ 
+     [CCode (cname = "gnutls_log_func", has_target = false)]
+     public delegate void LogFunc (int level, string msg);
+     [CCode (cname = "gnutls_global_set_log_function")]
+     public void set_log_function (LogFunc func);
+     [CCode (cname = "gnutls_global_set_log_level")]
+     public void set_log_level (int level);
+ 
+     [CCode (cname = "gnutls_transport_set_global_errno")]
+     public void set_global_errno (int err);
+ 
+ // SRP stuff
+ 
+     [CCode (cname = "gnutls_srp_server_credentials_function *", has_target = false)]
+     public delegate int SRPServerCredentialsFunction (Session session, string username,
+                                                        out Datum salt, out Datum verifier,
+                                                        out Datum generator, out Datum prime);
+ 
+     [Compact]
+     [CCode (cname = "struct gnutls_srp_server_credentials_st", free_function = "gnutls_srp_free_server_credentials")]
+     public class SRPServerCredentials
+     {
+         [CCode (cname = "gnutls_srp_allocate_server_credentials")]
+         private static int allocate (out SRPServerCredentials sc);
+         public static SRPServerCredentials create ()
+         {
+             SRPServerCredentials result = null;
+             var ret = allocate (out result);
+             if (ret != 0)
+                 GLib.error ("%s", ((ErrorCode)ret).to_string ());
+             return result;
+         }
+ 
+         [CCode (cname = "gnutls_srp_set_server_credentials_file")]
+         public int set_credentials_file (string password_file, string password_conf_file);
+ 
+         [CCode (cname = "gnutls_srp_server_get_username")]
+         public string get_username ();
+ 
+         [CCode (cname = "gnutls_srp_set_server_credentials_function")]
+         public void set_credentials_function (SRPServerCredentialsFunction func);
+     }
+ 
+     [CCode (cname = "gnutls_srp_client_credentials_function *", has_target = false)]
+     public delegate int SRPClientCredentialsFunction (Session session, out string username, out string password);
+ 
+     [Compact]
+     [CCode (cname = "struct gnutls_srp_client_credentials_st", free_function = "gnutls_srp_free_client_credentials")]
+     public class SRPClientCredentials
+     {
+         [CCode (cname = "gnutls_srp_allocate_client_credentials")]
+         private static int allocate (out SRPClientCredentials sc);
+         public static SRPClientCredentials create ()
+         {
+             SRPClientCredentials result;
+             var ret = allocate (out result);
+             if (ret != 0)
+                 GLib.error ("%s", ((ErrorCode)ret).to_string ());
+             return result;
+         }
+ 
+         [CCode (cname = "gnutls_srp_set_client_credentials")]
+         public int set_credentials (string username, string password);
+ 
+         [CCode (cname = "gnutls_srp_set_client_credentials_function")]
+         public void set_credentials_function (SRPClientCredentialsFunction func);
+     }
+ 
+     //  extern int gnutls_srp_verifier (const char *username,
+     //			  const char *password,
+     //			  const gnutls_datum_t * salt,
+     //			  const gnutls_datum_t * generator,
+     //			  const gnutls_datum_t * prime,
+     //			  gnutls_datum_t * res);
+ 
+     public int srp_verifier (string username, string password, /* const */ ref Datum salt, /* const */ ref Datum generator, /* const */ ref Datum prime, out Datum result);
+ 
+     // The static parameters defined in draft-ietf-tls-srp-05
+     // Those should be used as input to gnutls_srp_verifier().
+ 
+     public const Datum srp_2048_group_prime;
+     public const Datum srp_2048_group_generator;
+ 
+     public const Datum srp_1536_group_prime;
+     public const Datum srp_1536_group_generator;
+ 
+     public const Datum srp_1024_group_prime;
+     public const Datum srp_1024_group_generator;
+ 
+     public int srp_base64_encode (/* const */ ref Datum data, [CCode (array_length = "false")] char[] result, ref size_t result_size);
+     public int srp_base64_encode_alloc (/* const */ ref Datum data, out Datum result);
+ 
+     public int srp_base64_decode (/* const */ ref Datum b64_data, [CCode (array_length = false)] uint8[] result, ref size_t result_size);
+     public int srp_base64_decode_alloc (/* const */ ref Datum b64_data, out Datum result);
+ 
+ 
+ 
+ 
+ 
+ 
+ // PSK stuff
+ 
+     [CCode (cname = "gnutls_psk_key_flags", cprefix = "GNUTLS_PSK_KEY_", has_type_id = false)]
+     public enum PSKKeyFlags
+     {
+         RAW,
+         HEX
+     }
+ 
+     [CCode (cname = "gnutls_psk_server_credentials_function *", has_target = false)]
+     public delegate int PSKServerCredentialsFunction (Session session, string username, /* const */ ref Datum key);
+ 
+     [Compact]
+     [CCode (cname = "struct gnutls_psk_server_credentials_st", free_function = "gnutls_psk_free_server_credentials")]
+     public class PSKServerCredentials
+     {
+         [CCode (cname = "gnutls_psk_allocate_server_credentials")]
+         private static int allocate (out PSKServerCredentials sc);
+         public static PSKServerCredentials create ()
+         {
+             PSKServerCredentials result;
+             var ret = allocate (out result);
+             if (ret != 0)
+                 GLib.error ("%s", ((ErrorCode)ret).to_string ());
+             return result;
+         }
+ 
+         [CCode (cname = "gnutls_psk_set_server_credentials_file")]
+         public int set_credentials_file (string password_file);
+ 
+         [CCode (cname = "gnutls_psk_set_server_credentials_hint")]
+         public int set_credentials_hint (string hint);
+ 
+         [CCode (cname = "gnutls_psk_set_server_credentials_function")]
+         public void set_credentials_function (PSKServerCredentialsFunction func);
+ 
+         [CCode (cname = "gnutls_psk_set_server_dh_params")]
+         public void set_dh_params (DHParams dh_params);
+ 
+         [CCode (cname = "gnutls_psk_set_server_params_function")] // also gnutls_psk_set_params_function
+         public void set_params_function (ParamsFunction func);
+     }
+ 
+     [CCode (cname = "gnutls_psk_client_credentials_function *", has_target = false)]
+     public delegate int PSKClientCredentialsFunction (Session session, out string username, out Datum key);
+ 
+     [Compact]
+     [CCode (cname = "struct gnutls_psk_client_credentials_st", free_function = "gnutls_psk_free_client_credentials")]
+     public class PSKClientCredentials
+     {
+         [CCode (cname = "gnutls_psk_allocate_client_credentials")]
+         private static int allocate (out PSKClientCredentials sc);
+         public static PSKClientCredentials create ()
+         {
+             PSKClientCredentials result;
+             var ret = allocate (out result);
+             if (ret != 0)
+                 GLib.error ("%s", ((ErrorCode)ret).to_string ());
+             return result;
+         }
+ 
+         [CCode (cname = "gnutls_psk_set_client_credentials")]
+         public int set_credentials (string username, /* const */ ref Datum key, PSKKeyFlags format);
+ 
+         [CCode (cname = "gnutls_psk_set_client_credentials_function")]
+         public void set_credentials_function (PSKClientCredentialsFunction func);
+     }
+ 
+     public int hex_encode (/* const */ ref Datum data, [CCode (array_length = "false")] char[] result, ref size_t result_size);
+     public int hex_decode (/* const */ ref Datum hex_data, [CCode (array_length = "false")] char[] result, ref size_t result_size);
+ 
+     public int psk_netconf_derive_key (string password, string psk_identity, string psk_identity_hint, out Datum output_key);
+ 
+ ////
+ 
+     [SimpleType]
+     [CCode (cname = "gnutls_retr_st", has_type_id = false)]
+     public struct RetrStruct
+     {
+         public CertificateType type;
+         [CCode (cname = "cert.x509", array_length_cname = "ncerts", array_length_type = "unsigned int")]
+         public unowned X509.Certificate[] cert_x509;
+         [CCode (cname = "cert.pgp")]
+         public unowned OpenPGP.Certificate cert_pgp;
+         [CCode (cname = "key.x509")]
+         public unowned X509.PrivateKey key_x509;
+         [CCode (cname = "key.pgp")]
+         public unowned OpenPGP.PrivateKey key_pgp;
+         public uint deinit_all;
+     }
+ 
+     public int pem_base64_encode (string msg, /* const */ ref Datum data, void* result, ref size_t result_size);
+     public int pem_base64_decode (string header, /* const */ ref Datum b64_data, void* result, ref size_t result_size);
+ 
+     public int pem_base64_encode_alloc (string msg, /* const */ ref Datum data, out Datum result);
+     public int pem_base64_decode_alloc (string header, /* const */ ref Datum b64_data, out Datum result);
+ 
+     public int hex2bin (string hex_data, size_t hex_size, void* bin_data, ref size_t bin_size);
+ 
+     // returns cipher suite name or null if index is out of bounds
+     public unowned string? cipher_suite_info (size_t index, [CCode (array_length = "false")] char[] cs_id, out KXAlgorithm kx,
+                                              out CipherAlgorithm cipher, out MacAlgorithm mac,
+                                              out Protocol version);
+ 
+     public unowned string? cipher_suite_get_name (KXAlgorithm kx, CipherAlgorithm cipher, MacAlgorithm mac);
+ 
+     public int prf (Session session, size_t label_size, string label, bool server_random_first,
+                     size_t extra_size, void* extra, size_t output_size, void* output);
+ 
+     public int prf_raw (Session session, size_t label_size, string label,
+                         size_t seed_size, void* seed, size_t output_size, void* output);
+ 
+     // Gnutls error codes. The mapping to a TLS alert is also shown in comments.
+     [CCode (cname = "int", cprefix = "GNUTLS_E_", lower_case_cprefix = "gnutls_error_", has_type_id = false)]
+     public enum ErrorCode {
+ 
+         SUCCESS,
+         UNKNOWN_COMPRESSION_ALGORITHM,
+         UNKNOWN_CIPHER_TYPE,
+         LARGE_PACKET,
+         UNSUPPORTED_VERSION_PACKET,	// GNUTLS_A_PROTOCOL_VERSION
+         UNEXPECTED_PACKET_LENGTH,	// GNUTLS_A_RECORD_OVERFLOW
+         INVALID_SESSION,
+         FATAL_ALERT_RECEIVED,
+         UNEXPECTED_PACKET,	// GNUTLS_A_UNEXPECTED_MESSAGE
+         WARNING_ALERT_RECEIVED,
+         ERROR_IN_FINISHED_PACKET,
+         UNEXPECTED_HANDSHAKE_PACKET,
+         UNKNOWN_CIPHER_SUITE,	// GNUTLS_A_HANDSHAKE_FAILURE
+         UNWANTED_ALGORITHM,
+         MPI_SCAN_FAILED,
+         DECRYPTION_FAILED,	// GNUTLS_A_DECRYPTION_FAILED, GNUTLS_A_BAD_RECORD_MAC
+         MEMORY_ERROR,
+         DECOMPRESSION_FAILED,  // GNUTLS_A_DECOMPRESSION_FAILURE
+         COMPRESSION_FAILED,
+         AGAIN,
+         EXPIRED,
+         DB_ERROR,
+         SRP_PWD_ERROR,
+         INSUFFICIENT_CREDENTIALS,
+ 
+         HASH_FAILED,
+         BASE64_DECODING_ERROR,
+ 
+         MPI_PRINT_FAILED,
+         REHANDSHAKE,     // GNUTLS_A_NO_RENEGOTIATION
+         GOT_APPLICATION_DATA,
+         RECORD_LIMIT_REACHED,
+         ENCRYPTION_FAILED,
+ 
+         PK_ENCRYPTION_FAILED,
+         PK_DECRYPTION_FAILED,
+         PK_SIGN_FAILED,
+         X509_UNSUPPORTED_CRITICAL_EXTENSION,
+         KEY_USAGE_VIOLATION,
+         NO_CERTIFICATE_FOUND,	// GNUTLS_A_BAD_CERTIFICATE
+         INVALID_REQUEST,
+         SHORT_MEMORY_BUFFER,
+         INTERRUPTED,
+         PUSH_ERROR,
+         PULL_ERROR,
+         RECEIVED_ILLEGAL_PARAMETER,    // GNUTLS_A_ILLEGAL_PARAMETER
+         REQUESTED_DATA_NOT_AVAILABLE,
+         PKCS1_WRONG_PAD,
+         RECEIVED_ILLEGAL_EXTENSION,
+         INTERNAL_ERROR,
+         DH_PRIME_UNACCEPTABLE,
+         FILE_ERROR,
+         TOO_MANY_EMPTY_PACKETS,
+         UNKNOWN_PK_ALGORITHM,
+ 
+         // returned if libextra functionality was requested but
+         // gnutls_global_init_extra() was not called.
+ 
+         INIT_LIBEXTRA,
+         LIBRARY_VERSION_MISMATCH,
+ 
+         // returned if you need to generate temporary RSA
+         // parameters. These are needed for export cipher suites.
+ 
+         NO_TEMPORARY_RSA_PARAMS,
+ 
+         LZO_INIT_FAILED,
+         NO_COMPRESSION_ALGORITHMS,
+         NO_CIPHER_SUITES,
+ 
+         OPENPGP_GETKEY_FAILED,
+         PK_SIG_VERIFY_FAILED,
+ 
+         ILLEGAL_SRP_USERNAME,
+         SRP_PWD_PARSING_ERROR,
+         NO_TEMPORARY_DH_PARAMS,
+ 
+         // For certificate and key stuff
+ 
+         ASN1_ELEMENT_NOT_FOUND,
+         ASN1_IDENTIFIER_NOT_FOUND,
+         ASN1_DER_ERROR,
+         ASN1_VALUE_NOT_FOUND,
+         ASN1_GENERIC_ERROR,
+         ASN1_VALUE_NOT_VALID,
+         ASN1_TAG_ERROR,
+         ASN1_TAG_IMPLICIT,
+         ASN1_TYPE_ANY_ERROR,
+         ASN1_SYNTAX_ERROR,
+         ASN1_DER_OVERFLOW,
+         OPENPGP_UID_REVOKED,
+         CERTIFICATE_ERROR,
+         CERTIFICATE_KEY_MISMATCH,
+         UNSUPPORTED_CERTIFICATE_TYPE,	// GNUTLS_A_UNSUPPORTED_CERTIFICATE
+         X509_UNKNOWN_SAN,
+         OPENPGP_FINGERPRINT_UNSUPPORTED,
+         X509_UNSUPPORTED_ATTRIBUTE,
+         UNKNOWN_HASH_ALGORITHM,
+         UNKNOWN_PKCS_CONTENT_TYPE,
+         UNKNOWN_PKCS_BAG_TYPE,
+         INVALID_PASSWORD,
+         MAC_VERIFY_FAILED,	// for PKCS #12 MAC
+         CONSTRAINT_ERROR,
+ 
+         WARNING_IA_IPHF_RECEIVED,
+         WARNING_IA_FPHF_RECEIVED,
+ 
+         IA_VERIFY_FAILED,
+ 
+         UNKNOWN_ALGORITHM,
+ 
+         BASE64_ENCODING_ERROR,
+         INCOMPATIBLE_CRYPTO_LIBRARY,
+         INCOMPATIBLE_LIBTASN1_LIBRARY,
+ 
+         OPENPGP_KEYRING_ERROR,
+         X509_UNSUPPORTED_OID,
+ 
+         RANDOM_FAILED,
+         BASE64_UNEXPECTED_HEADER_ERROR,
+ 
+         OPENPGP_SUBKEY_ERROR,
+ 
+         CRYPTO_ALREADY_REGISTERED,
+ 
+         HANDSHAKE_TOO_LARGE,
+ 
+         UNIMPLEMENTED_FEATURE,
+ 
+         APPLICATION_ERROR_MAX, // -65000
+         APPLICATION_ERROR_MIN;  // -65500
+ 
+         [CCode (cname = "gnutls_error_is_fatal")]
+         public bool is_fatal ();
+         [CCode (cname = "gnutls_error_to_alert")]
+         public AlertDescription to_alert (out AlertLevel level);
+         [CCode (cname = "gnutls_perror")]
+         public void print ();
+         [CCode (cname = "gnutls_strerror")]
+         public unowned string to_string ();
+     }
+ }
+ 
+ 
+ 

+ 72 - 0
src/tests/CertifiedNameInfoTests.vala

@@ -0,0 +1,72 @@
+using Riddle;
+
+void certified_name_info_tests() {
+
+    Test.add_func("/name_info/certified/aa", () => {
+        var key = GnuTLS.X509.PrivateKey.create();
+        var data = new uint8[5120];
+        size_t data_size = data.length;
+        key.generate(GnuTLS.PKAlgorithm.RSA, 4096, 0);
+        key.export_pkcs8(GnuTLS.X509.CertificateFormat.PEM, "test", GnuTLS.X509.PKCSEncryptFlags.PLAIN, data, ref data_size);
+        data.length = (int)data_size;
+
+        print(@"Data length: $(data.length)\n$((string)data)\n");
+
+
+        var cert = GnuTLS.X509.Certificate.create();
+        var certtext = """-----BEGIN CERTIFICATE-----
+        MIIF6jCCBNKgAwIBAgISA4HuPZMyi+4cCoxukSS41jFGMA0GCSqGSIb3DQEBCwUA
+        MDIxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1MZXQncyBFbmNyeXB0MQswCQYDVQQD
+        EwJSMzAeFw0yMzA4MTMwNjQ1MTJaFw0yMzExMTEwNjQ1MTFaMBoxGDAWBgNVBAMT
+        D2JpbGx5LmJhcnJvdy5uejCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIB
+        AL+0rwsDOptRGIHjIgfxEH5iopyTNksDEt+R4W2zqpM3A191w37XH1A1PtB3NaRW
+        /x5cmGiFap9djVS/7yqAF/HhohWF5GEPdYkvD2r1MeA5D741FfMo1As1tb+m26Tm
+        qwX0ZTIGxys6t00KSjg05acohhG84PuA2KtwN8y2SG8V7sDXuzFvvWu5Pr//fbTT
+        PBM2RjFdBE0vVdJi7oZykagtL6sFumT+W1oKkwE5krIGKBSBFNqRlGsBS1Lc+w/5
+        gQaoEK3KbhsVZ2RXxI3hqhzQU4/ZzuWCWrlPBlBsb0YA5Egi+hQpbk061CEvFAr7
+        57QxuIWTyUh7aUEob79CTQDzni2eGwRN3s8MDmiTXfr7S+aISCdiim6Noj3IFbhk
+        +kYibJkDRyNTlrpjbJcd2fgQxcFo9uvXnrJRFq1ij31K+Bs7JAqydbjaci3YeZEt
+        zGetneX58uYAuKQ1vHYtjrxyagp55g/zgjb1xmWgNvr3QTeaWwlpKVkmMv6ngQNh
+        OE3gs5B1F9jPKczRFusboULBClG2QcRxnMrVcXSqDW3Io/F/TwuDY8RUx3Kavg2t
+        yoSQ9mGaWFE8jtafgsLDnZ/YJOlBFBsiIa4jlMRRPzwJCVhbTuNJ8w5uChGLEtE1
+        qoFlP4iHzOxLdj372fBsqsYsz7+CIjRQMAVidScS67tdAgMBAAGjggIQMIICDDAO
+        BgNVHQ8BAf8EBAMCBaAwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMAwG
+        A1UdEwEB/wQCMAAwHQYDVR0OBBYEFMFSUEY8xxRI6X93tZu6lYMytaQpMB8GA1Ud
+        IwQYMBaAFBQusxe3WFbLrlAJQOYfr52LFMLGMFUGCCsGAQUFBwEBBEkwRzAhBggr
+        BgEFBQcwAYYVaHR0cDovL3IzLm8ubGVuY3Iub3JnMCIGCCsGAQUFBzAChhZodHRw
+        Oi8vcjMuaS5sZW5jci5vcmcvMBoGA1UdEQQTMBGCD2JpbGx5LmJhcnJvdy5uejAT
+        BgNVHSAEDDAKMAgGBmeBDAECATCCAQMGCisGAQQB1nkCBAIEgfQEgfEA7wB2ALc+
+        +yTfnE26dfI5xbpY9Gxd/ELPep81xJ4dCYEl7bSZAAABie3bL8oAAAQDAEcwRQIg
+        K0N0VDsMQwbdSwIGCSu/DEUSIA5vmfRWd1HIO162K6ECIQDnSrrzAuF+CrSj1PNw
+        IpGPRxakZ1xZstCipPOUWB4f0AB1AOg+0No+9QY1MudXKLyJa8kD08vREWvs62nh
+        d31tBr1uAAABie3bL8kAAAQDAEYwRAIgDyAPAeDwM0r/okDio+cSdmxiciTI8TsU
+        CunXVrF62ewCIGDBlm1aYwXQkyXLZSf5TZUzrVYrDIYYAQDPUPBsAe8tMA0GCSqG
+        SIb3DQEBCwUAA4IBAQBkk3QzslFnW0zGOFOCyhTSUPQ5ZS32Czd5yGlwXg+iC8Ta
+        e3kh+svQu+NzQiYWCoY+LCHR8dv+tzvU7m8LfiNSDTqSvrb0w/16YDifr7bIFiH+
+        8NZUO/oIuXu3AkQpi0xXSsa1ohkDRPG9MZI1AXC1z+Ljw9rwgT9wbcLXBssbDssI
+        iCqT/DA2/mVM5qA6touGjsjhCG6w+QlQdV0f3Kp+sDQMd70eZfboZtw7LCXzceAS
+        unO4ZegZ9adeVTrPcNfCwvgOxtwwNz0s7vIhLa3xRU6F9WAgP4i7csG+O9cGZ1v0
+        J971OMv2WVcQsK83qDlbcTdJL1F6tdDbnl3YqJAR
+        -----END CERTIFICATE-----""";
+        var certdatum = as_datum(certtext.data);
+        cert.import(ref certdatum, GnuTLS.X509.CertificateFormat.PEM);
+
+        //  cert.set_key(key);
+        //  cert.set_expiration_time((time_t)new DateTime.now_utc().add_days(5).to_unix());
+
+        var info = new CertifiedNameInfo("barrow.nz", key, (owned)cert, new GnuTLS.X509.Certificate[0], Invercargill.empty<NameProperty>());
+
+        var encoded = info.get_encoded();
+        print(@"Encoded certified name: $encoded\n");
+
+        var info2 = new CertifiedNameInfo.from_string (encoded);
+
+    });
+}
+
+private static GnuTLS.Datum as_datum(uint8[] data) {
+    return GnuTLS.Datum() {
+        data = data,
+        size = data.length
+    };
+}

+ 1 - 0
src/tests/TestRunner.vala

@@ -6,6 +6,7 @@ public static int main(string[] args) {
     shared_key_pair_riddle_tests();
     identity_riddle_tests();
     decentralised_name_info_tests();
+    certified_name_info_tests();
 
     Test.run();
 

+ 1 - 0
src/tests/meson.build

@@ -3,5 +3,6 @@ sources = files('TestRunner.vala')
 sources += files('SharedKeyPairRiddleTests.vala')
 sources += files('IdentityRiddleTests.vala')
 sources += files('DecentralisedNameInfoTests.vala')
+sources += files('CertifiedNameInfoTests.vala')
 
 executable('riddle-test-suite', sources, dependencies: dependencies, install: false)