¶ VADß EThis file consists of binary data and should not be touched by hands!¶ STICKERß Hã
¶ certgen_html/certgen_svc.sqlß S'--
-- Registry keys:
-- certgen_cert_comment - comment to add in generated keys (default is )
--
use CERT;
create procedure
get_cid (in key_name varchar)
{
declare carr any;
carr := sprintf_inverse (key_name, 'cert_gen_key_%d', 0);
return (carr [0]);
}
;
create procedure
save_cert (in k varchar)
{
declare carr any;
declare cid varchar;
-- dbg_printf ('in save_cert, k: %s', k);
cid := CERT..get_cid (k);
insert replacing CERT..CERTIFICATES (C_ID, C_CERT) values (cid, decode_base64 (xenc_X509_certificate_serialize (k)));
return cid;
}
;
create procedure
get_cert (in k varchar)
{
declare carr any;
declare cid varchar;
-- dbg_printf ('in get_cert');
carr := sprintf_inverse (k, 'cert_gen_key_%d', 0);
cid := carr [0];
declare cert long varchar;
declare exit handler for sqlstate '*' {
return null;
};
select C_CERT into cert from CERT..CERTIFICATES where C_ID = cid;
return cert;
}
;
create procedure
gen_cert_parms (inout ext any, inout ku any, inout ca any)
{
ca := 'CA:FALSE';
if (ext = 'ca')
{
ca := 'CA:TRUE';
ext := null;
}
ca := 'critical,' || ca;
if (length (ext))
ext := 'critical, ' || ext;
if (strstr (ext, 'emailProtection'))
ku := vector ('keyUsage', 'critical, digitalSignature, keyEncipherment');
else
ku := vector ();
-- dbg_printf ('gen_cert_params: ca');
-- dbg_printf ('ca: %s, ext, ku:', ca);
-- dbg_obj_print (ext);
-- dbg_obj_print (ku);
return;
}
;
create procedure certgen_cert_valid_days_init ()
{
if (isstring (registry_get ('certgen_cert_valid_days')))
return;
registry_set ('certgen_cert_valid_days', '90');
}
;
certgen_cert_valid_days_init ()
;
create procedure
get_cert_dur ()
{
declare cert_dur integer;
cert_dur := registry_get ('certgen_cert_valid_days');
if (0 = cert_dur)
cert_dur := 365; -- Default is 365 days
else
cert_dur := atoi (cert_dur);
return cert_dur;
}
;
create procedure
set_json_out_hdr ()
{
http_rewrite();
http_header ('Content-Type: application/json\r\n');
}
;
create procedure
ensure_parm (in params any, in parm varchar, in status_code integer, in status_title varchar, in error_text varchar)
{
declare val varchar;
val := get_keyword (parm, params, null);
if (val is null) {
http_status_set(status_code);
http (sprintf ('
%d %s
%s
%s
', status_code, status_title, status_title, error_text));
return null;
}
return val;
}
;
create procedure
get_cert_comment ()
{
declare ns_comment varchar;
ns_comment := registry_get ('certgen_cert_comment');
if (0 = ns_comment) ns_comment := 'Certificate Generated by OpenLink Virtuoso';
}
;
create procedure
generate_key (in key_name varchar,
in strength integer)
{
if (xenc_key_exists (key_name)) xenc_key_remove (key_name);
xenc_key_RSA_create (key_name, strength);
return key_name;
}
;
create procedure
sign_and_make_cert (in ca_key varchar,
in key_name varchar,
in cn varchar,
in o varchar,
in c varchar,
in st varchar,
in email varchar,
in ca varchar,
in san varchar,
in ext_key_usage varchar,
in key_usage varchar,
in cipher varchar)
{
declare cert_comment varchar;
cert_comment := registry_get ('certgen_cert_comment');
if (0 = cert_comment) cert_comment := 'Certificate Generated by OpenLink Virtuoso';
declare cert_dur integer;
cert_dur := CERT..get_cert_dur(); -- no days cert will be valid
-- dbg_printf ('sign_and_make_cert: cn: %s', cn);
--dbg_obj_print_vars (cn,o,c,st);
xenc_x509_generate (ca_key, key_name, sequence_next ('ca_id_rsa'), cert_dur,
vector ('CN', cn,
'O', o,
'C', c,
'ST', st,
'emailAddress', email),
vector_concat (vector ('basicConstraints', 'critical,' || ca,
'subjectAltName', san,
'nsComment', cert_comment,
-- 'authorityKeyIdentifier', 'keyid,issuer:always',
'extendedKeyUsage', ext_key_usage), key_usage),
0, cipher);
return key_name;
}
;
create procedure
self_sign_and_make_cert (in key_name varchar,
in cn varchar,
in o varchar,
in c varchar,
in st varchar,
in email varchar,
in ca varchar,
in san varchar,
in ext_key_usage varchar,
in key_usage varchar,
in cipher varchar)
{
-- dbg_printf ('self_sign_and_make_cert: san: %s', san);
declare cert_comment varchar;
cert_comment := registry_get ('certgen_cert_comment');
if (0 = cert_comment) cert_comment := 'Certificate Generated by OpenLink Virtuoso';
declare cert_dur integer;
cert_dur := CERT..get_cert_dur(); -- no days cert will be valid
xenc_x509_ss_generate (key_name, 0, cert_dur,
vector ('CN', cn,
'O', o,
'C', c,
'ST', st,
'emailAddress', email),
vector_concat (vector ('basicConstraints', ca,
'subjectAltName', san,
'nsComment', cert_comment,
-- 'authorityKeyIdentifier', 'keyid,issuer:always',
'extendedKeyUsage', ext_key_usage), key_usage),
0, cipher);
return key_name;
}
;
create procedure
mangle_modulus (in mod varchar)
{
declare newmod varchar;
newmod := '';
for (declare i int, i := 0; i < length (mod); i := i + 70)
{
newmod := concat (newmod, subseq (mod, i, i + 70), '\n\t');
}
return newmod;
}
;
create procedure
get_sparql_ep (in webid varchar, in use_proxy int)
{
declare gr, tmpg, sp_ep, pb_ep varchar;
tmpg := uuid();
gr := CERT..remove_frag (webid);
sp_ep := null;
pb_ep := '';
tmpg := uuid ();
exec (sprintf ('sparql load <%s> into <%s>', gr, tmpg));
for select "ds", "ep", "pb" from (
sparql select ?ds ?ep ?pb where
{
graph `iri (?:tmpg)` {
?s ?ds .
?ds ?ep .
optional { ?s ?pb . } .
}
}
) x do
{
sp_ep := sprintf ('%s?default-graph-uri=%U', "ep", "ds");
pb_ep := "pb";
}
exec (sprintf ('sparql clear graph <%s>', tmpg));
if (sp_ep is null)
{
if (use_proxy)
sp_ep := sprintf ('http://%{WSHost}s/sparql-auth?default-graph-uri=%s', gr);
else
sp_ep := sprintf ('http://%{WSHost}s/sparql-auth?default-graph-uri=%s',
sprintf ('http://%{WSHost}s/dataspace'));
}
return vector (sp_ep, pb_ep);
}
;
create procedure
get_cert_info (in key_name varchar,
in webid varchar,
in digest_type varchar,
in fmt varchar := 'json')
{
declare cert_fingerprint, cert_pubkey_type, cert_modulus, cert_exponent varchar;
declare cert_pubkey, info any;
declare cert_serial, cert_subject, cert_issuer, cert_val_not_before, cert_val_not_after varchar;
declare tag varchar;
declare san varchar;
--dbg_printf ('get_cert_info key_name: %s, digest_type: %s, webid: %s', key_name, digest_type, webid);
cert_pubkey := xenc_pem_export (key_name, 0);
cert_serial := get_certificate_info (1, cert_pubkey, 0);
cert_subject := get_certificate_info (2, cert_pubkey, 0);
cert_issuer := get_certificate_info (3, cert_pubkey, 0);
cert_val_not_before := get_certificate_info (4, cert_pubkey, 0);
cert_val_not_after := get_certificate_info (5, cert_pubkey, 0);
cert_fingerprint := get_certificate_info (6, cert_pubkey, 0, null, digest_type);
cert_fingerprint := replace (cert_fingerprint, ':', '');
-- dbg_printf ('fingerprint: %s', cast (fingerprint as varchar));
info := get_certificate_info (9, cast (cert_pubkey as varchar), 0);
san := get_certificate_info (7, cast (cert_pubkey as varchar),0,null,'2.5.29.17');
cert_pubkey_type := info[0];
cert_exponent := info[1];
cert_modulus := bin2hex(info[2]);
tag := CERT..tag (cert_fingerprint, webid, digest_type, fmt);
declare ret_val varchar;
if (fmt = 'json')
{
ret_val := sprintf ('{"san":"%s","key_name":"%s",\n"pubkey_type":"%s",\n"pubkey":"%U",\n"modulus":"%s",\n"digest_type":"%s",\n"fingerprint":"%s",\n"exponent":%d,\n"serial":"%s",\n"subject":"%U",\n"issuer":"%U",\n"val_not_before":"%s",\n"val_not_after":"%s",\n"tag":"%s"}',
san,
key_name,
cert_pubkey_type,
cert_pubkey,
cert_modulus,
digest_type,
cert_fingerprint,
cert_exponent,
cert_serial,
cert_subject,
cert_issuer,
cert_val_not_before,
cert_val_not_after,
tag);
-- dbg_printf ('get_cert_info: %s', ret_val);
return ret_val;
}
else if (fmt = 'sparql')
return make_cert_info_sparql_stmt (key_name,
webid,
cert_modulus,
digest_type,
cert_fingerprint,
cert_exponent,
cert_serial,
cert_subject,
cert_issuer,
cert_val_not_before,
cert_val_not_after,
tag);
else
return vector ('key_name', key_name,
'pubkey_type', cert_pubkey_type,
'pubkey' , cert_pubkey,
'modulus', cert_modulus,
'digest_type', digest_type,
'fingerprint', cert_fingerprint,
'exponent', cert_exponent,
'serial', cert_serial,
'subject', cert_subject,
'issuer', cert_issuer,
'val_not_before', cert_val_not_before,
'val_not_after', cert_val_not_after,
'tag', tag);
}
;
create procedure
make_cert_info_sparql_stmt (in key_name varchar,
in webid varchar,
in modulus varchar,
in digest_type varchar,
in fingerprint varchar,
in exponent varchar,
in serial varchar,
in subject varchar,
in issuer varchar,
in val_not_before varchar,
in val_not_after varchar,
in tag varchar)
{
declare key_iri, cer_iri, cid varchar;
--key_iri := rtrim (webid, '#this') || '#' || fingerprint;
cid := CERT..get_cid (key_name);
key_iri := sprintf ('http://%{WSHost}s/certgen/key/%d', cid); --CERT..remove_frag (w) || '#key' || fp;
cer_iri := CERT..remove_frag (webid) || '#cert' || replace (fingerprint, ':', '');
declare stmt varchar;
stmt := sprintf ('
PREFIX rsa:
PREFIX cert:
PREFIX oplcert:
PREFIX xsd:
INSERT
{
<%s> cert:key <%s> .
<%s> a cert:RSAPublicKey ;
cert:modulus "%s"^^xsd:hexBinary ;
cert:exponent "%d"^^xsd:int .
<%s> oplcert:hasCertificate <%s> .
<%s> a oplcert:Certificate ;
oplcert:fingerprint "%s" ;
oplcert:fingerprint-digest "%s" ;
oplcert:subject "%s" ;
oplcert:issuer "%s" ;
oplcert:notBefore "%s"^^xsd:dateTime ;
oplcert:notAfter "%s"^^xsd:dateTime ;
oplcert:serial "%s" ;
oplcert:digestURI <%s> ;
oplcert:hasPublicKey <%s> .
}
', webid, key_iri,
key_iri, modulus, exponent,
webid, cer_iri,
cer_iri, fingerprint, digest_type, subject, issuer, DB..date_iso8601 (DB..X509_STRING_DATE (val_not_before)), DB..date_iso8601 (DB..X509_STRING_DATE (val_not_after)), serial, tag, key_iri);
-- dbg_printf ('%s', stmt);
return stmt;
}
;
create procedure
save_cert_sparql (in ep varchar,
in uid varchar,
in pwd varchar,
in webid varchar,
in key_name varchar,
in digest_type varchar)
{
if (length (uid) = 0)
{
uid := null;
pwd := null;
}
declare req varchar;
req := CERT..get_cert_info (key_name, webid, digest_type, 'sparql');
declare headers any;
declare body varchar;
body := http_client_ext (url=>ep, headers=>headers, http_method=>'POST',
body=>sprintf ('query=%U', req), uid=>uid, pwd=>pwd);
-- dbg_printf ('%s', req);
-- dbg_obj_print (headers);
if (isvector (headers) and headers[0] not like 'HTTP/1._ 200 %')
signal ('OCG00', body);
else
return 0;
}
;
--
-- get blog or atom endpoint URL, return endpoint URL
--
create procedure
detect_atom_endpoint (in url varchar)
{
declare parse_arr any;
declare host varchar;
declare ret_hdr varchar;
declare ep, wp varchar;
declare c, xt, xp any;
parse_arr := rfc1808_parse_uri (url);
host := concat (parse_arr[0], '://', parse_arr[1]);
declare exit handler for sqlstate '*' {
ep := host;
return ep;
};
c := http_get (url, ret_hdr);
xt := xtree_doc (c, 2);
xp := xpath_eval ('/html/head/link[@rel="alternate" and @type="application/atomserv+xml"]/@href', xt);
xp := cast (xp as varchar);
if (length (xp)) -- got link
{
c := http_get (cast (xp as varchar), ret_hdr);
xt := xtree_doc (c);
xp := xpath_eval ('/service/workspace/collection/@href', xt);
if (xp is not null)
ep := cast (xp as varchar);
}
wp := xpath_eval ('//meta[@name="generator"]/@content', xt);
wp := lower (cast (wp as varchar));
if (wp = 'wordpress.com')
ep := host || '/wp-app.php/posts';
-- dbg_printf ('detect_atom_endpoint: ep; %s', ep);
return ep;
}
;
create procedure
get_atom_post_url (in endpoint varchar)
{
return;
}
;
create procedure
atom_post (in endpoint varchar,
in uid varchar,
in pwd varchar,
in content varchar,
in title varchar)
{
declare error_message, post_id varchar;
declare req BLOG.DBA."blogRequest";
declare exit handler for sqlstate '*' {
-- dbg_obj_print (__SQL_MESSAGE);
error_message := 'Cannot create a post, verify endpoint and credentials';
return null;
};
-- dbg_printf ('atom_post: endpoint: %s', endpoint);
req := BLOG.DBA."blogRequest" ('appKey', null, '', uid, pwd);
req.struct := CERT..BLOG_MESSAGE (uid, content, '', now (), title);
post_id := blog.atom.new_Post (endpoint, req);
-- dbg_obj_print_vars (post_id);
return post_id;
}
;
create procedure
atom_post_edit (in endpoint varchar,
in uid varchar,
in pwd varchar,
in post_id varchar,
in post_content varchar,
in title varchar)
{
declare rc varchar;
declare req BLOG.DBA."blogRequest";
-- dbg_printf ('in atom_post_edit');
req := BLOG.DBA."blogRequest" ('appKey', '', post_id, uid, pwd);
req.struct := CERT..BLOG_MESSAGE (uid, post_content, post_id, now (), 'WebID');
rc := blog.atom.edit_Post (post_id, req);
-- if (rc)
-- log_msg := 'Post successful';
-- else
-- err := 'Post failed';
-- dbg_obj_print (rc);
return rc;
}
;
--
-- Receipt of - made key needs be handled in submit
--
create procedure
handle_browser_gen_key (inout lines any, inout params any)
{
declare cn, o, c, st, san varchar;
declare email varchar;
declare ext_key_usage varchar;
declare key_usage varchar;
declare ca varchar;
declare use_proxy int;
declare key_name, cid varchar;
declare key_len varchar;
declare cipher varchar;
declare pk any;
declare multipart varchar;
--dbg_obj_print_vars (params);
cn := {?'cn'};
o := {?'o'};
c := {?'c'};
st := {?'st'};
email := {?'email'};
san := {?'webid'};
ext_key_usage := {?'purpose'};
cipher := {?'cipher'};
key_len := atoi({?'key_len'});
key_name := {?'key_name'};
multipart := {?'multipart'};
use_proxy := atoi (get_keyword ('prx', params, '0'));
if (use_proxy)
san := DB.DBA.RDF_PROXY_ENTITY_IRI (CERT..remove_frag (san));
pk := replace (get_keyword ('pubkey', params), '\r\n', '');
pk := replace (pk, '\n', '');
pk := replace (pk, '\r', '');
san := 'URI:' || san;
if (email is not null and email <> '')
{
san := san || ', email:' || email;
san := ltrim (san, ', ');
}
if (key_name = '' or key_name is null)
{
key_name := sprintf ('cert_gen_key_%d', sequence_next ('cert_gen_key_seq'));
}
if (xenc_key_exists (key_name)) xenc_key_remove (key_name); -- XXX may be exploitable by vandals
xenc_SPKI_read (key_name, pk); -- read and store public key submitted from keygen
CERT..gen_cert_parms (ext_key_usage, key_usage, ca); -- Side effects warning - inout params
CERT..sign_and_make_cert ('id_rsa', key_name, cn, o, c, st, email, ca, san, ext_key_usage, key_usage, cipher);
cid := CERT..save_cert (key_name);
http_rewrite ();
declare boundary varchar;
if (multipart = 'yes')
{
boundary := sprintf ('=_cert_gen_next_part_%s',md5(datestring (now())));
http_header (sprintf ('Content-Type: multipart/mixed; boundary=%s\r\n', boundary));
http ('--' || boundary || '\r\n');
http ('Content-Type: application/x-x509-user-cert\r\n\r\n');
}
else
{
http_header ('Content-Type: application/x-x509-user-cert\r\n');
}
http (decode_base64 (xenc_X509_certificate_serialize (key_name)));
if (multipart = 'yes') {
http ('\r\n--' || boundary || '\r\n');
connection_set ('certgen_cert_multi_boundary', boundary);
http ('Content-Type: text/html; charset=UTF-8\r\n\r\n');
}
return key_name;
}
;
create procedure
handle_atom_endpoint (in blog varchar, in usr varchar, in pwd varchar)
{
declare host, blogs, webid, email, name, post_id, ep, error_message, wp varchar;
declare h any;
h := rfc1808_parse_uri (blog);
host := concat (h[0], '://', h[1]);
ep := null;
error_message := '';
declare c, xt, xp any;
declare exit handler for sqlstate '*' {
ep := null;
goto err_end;
};
h := null;
c := http_get (blog, h);
xt := xtree_doc (c, 2);
xp := xpath_eval ('/html/head/link[@rel="alternate" and @type="application/atomserv+xml"]/@href', xt);
xp := cast (xp as varchar);
if (length (xp))
{
c := http_get (cast (xp as varchar), h);
xt := xtree_doc (c);
xp := xpath_eval ('/service/workspace/collection/@href', xt);
if (xp is not null)
ep := cast (xp as varchar);
}
wp := xpath_eval ('//meta[@name="generator"]/@content', xt);
wp := lower (cast (wp as varchar));
if (wp = 'wordpress.com')
ep := host || '/wp-app.php/posts';
else if (ep is null)
ep := null;
err_end:
webid := email := name := post_id := '';
if (ep is not null)
{
declare post any;
declare req BLOG.DBA."blogRequest";
declare exit handler for sqlstate '*' {
--dbg_obj_print (__SQL_MESSAGE);
error_message := 'Cannot create a post, verify endpoint and credentials';
goto err_end1;
};
req := BLOG.DBA."blogRequest" ('appKey', null, '', usr, pwd);
req.struct := CERT..BLOG_MESSAGE (usr, 'WebID place-holder, generation in progress', '', now (), 'WebID');
post_id := blog.atom.new_Post (ep, req);
post := http_client (post_id, usr, pwd);
post := xtree_doc (post);
webid := cast (xpath_eval ('//entry/link/@href', post) as varchar);
email := cast (xpath_eval ('//entry/author/email/text()', post) as varchar);
name := cast (xpath_eval ('//entry/author/name/text()', post) as varchar);
}
err_end1:
return vector (ep, post_id, webid, email, name);
}
;
¶ certgen_html/vh.sqlß DB.DBA.VHOST_REMOVE (lpath=>'/certgen');
DB.DBA.VHOST_DEFINE (lpath=>'/certgen', ppath=>registry_get ('_certgen_html_path_'), vsp_user=>'dba', is_dav=>case when registry_get ('_certgen_html_path_') like '/DAV/%' then 1 else 0 end, is_brws=>1, def_page=>'start.vsp');
¶ certgen_html/wf.sqlß A‰use CERT;
DB.DBA.wa_exec_no_error_log (
'create table OPENID_SESSIONS
(
SS_HANDLE varchar,
SS_KEY_NAME varchar,
SS_KEY varbinary,
SS_KEY_TYPE varchar,
SS_EXPIRY datetime,
SS_ASSOCIATION_TYPE varchar,
SS_SESSION_TYPE varchar,
primary key (SS_HANDLE)
)');
DB.DBA.wa_exec_no_error_log (
'create table CERTIFICATES (C_ID int primary key, C_CERT long varchar, C_SHA1 varchar, C_MD5 varchar)'
);
DB.DBA.wa_add_col('CERT.DBA.CERTIFICATES', 'C_SHA1', 'varchar');
DB.DBA.wa_add_col('CERT.DBA.CERTIFICATES', 'C_MD5', 'varchar');
DB.DBA.wa_exec_no_error_log ('create index CERTIFICATES_MD5 on CERTIFICATES (C_MD5)');
DB.DBA.wa_exec_no_error_log ('create index CERTIFICATES_SHA1 on CERTIFICATES (C_SHA1)');
create procedure openid_discover (in uri varchar)
{
declare xuri, cnt, hdr, xt, xp, srv, srv2, ident, delegate, reg, ver any;
ident := uri;
again:
cnt := DB.DBA.HTTP_CLIENT_EXT (url=>uri, headers=>hdr, n_redirects=>10);
reg := 'http://openid.net/sreg/1.0';
ver := 1;
if (http_request_header (hdr, 'Content-Type') = 'application/xrds+xml')
{
declare top_priority int;
xt := xtree_doc (cnt);
xp := xpath_eval ('/XRDS/XRD/Service[Type/text() = "http://specs.openid.net/auth/2.0/signon" or Type/text() = "http://specs.openid.net/auth/2.0/server"
or Type/text() = "http://openid.net/signon/1.1" or Type/text() = "http://openid.net/signon/1.0"]', xt, 0);
top_priority := -1;
srv := null;
foreach (any srvx in xp) do
{
declare priority int;
priority := cast (xpath_eval ('@priority', srvx) as int);
if (top_priority = -1 or top_priority > priority or srv is null)
{
top_priority := priority;
srv := cast (xpath_eval ('URI/text()', srvx) as varchar);
if (xpath_eval ('Type[ . = "http://specs.openid.net/auth/2.0/signon" or . = "http://specs.openid.net/auth/2.0/server"]', srvx) is not null)
ver := 2;
else
ver := 1;
if (xpath_eval ('Type[ . = "http://openid.net/srv/ax/1.0"]', srvx) is not null)
reg := 'http://openid.net/srv/ax/1.0';
else if (xpath_eval ('Type[ . = "http://openid.net/sreg/1.0"]', srvx) is not null)
reg := 'http://openid.net/sreg/1.0';
}
}
}
else
{
xuri := http_request_header (hdr, 'X-XRDS-Location');
if (length (xuri))
{
uri := xuri;
goto again;
}
xt := xtree_doc (cnt, 2);
srv := cast (xpath_eval ('//link[contains (@rel, "openid.server")]/@href', xt) as varchar);
srv2 := cast (xpath_eval ('//link[contains (@rel, "openid2.provider")]/@href', xt) as varchar);
delegate := cast (xpath_eval ('//link[contains (@rel, "openid.delegate")]/@href', xt) as varchar);
if (srv2 is not null)
{
srv := srv2;
ver := 2;
}
if (delegate is not null)
ident := delegate;
}
return vector (ver, srv, reg, ident);
}
;
create procedure openid_parse_ax (in pars any)
{
declare pref, pname varchar;
declare pos int;
declare res any;
pos := position ('http://openid.net/srv/ax/1.0', pars);
if (pos < 2)
return null;
pref := pars [pos - 2];
if (pref not like 'openid.ns.%')
return null;
pref := subseq (pref, 10);
pref := 'openid.' || pref || '.value.';
res := vector ();
for (declare i int, i := 0; i < length (pars); i := i + 2)
{
if (pars[i] like pref || '%')
{
pname := subseq (pars[i], length (pref));
if (pname like '%.%')
pname := subseq (pname, 0, strchr (pname, '.'));
res := vector_concat (res, vector (pname, pars[i+1]));
}
}
return res;
}
;
create procedure register_trusted_email (in email varchar)
{
declare digest, id, ep, webid varchar;
digest := sha1_digest (email);
id := sprintf ('http://%{URIQADefaultHost}s/mv/data/') || bin2hex (cast (decode_base64 (digest) as varbinary));
webid := id || '#this';
ep := sprintf ('http://%{URIQADefaultHost}s/sparql-auth/');
sparql prefix foaf: insert into graph iri ('http://localhost/mv')
{
`iri (?:webid)` a foaf:Person .
`iri (?:id)` a foaf:Document .
`iri (?:id)` .
`iri(?:ep)` .
`iri (?:id)` foaf:primaryTopic `iri(?:webid)` .
`iri(?:webid)` foaf:mbox_sha1sum ?:digest .
};
return webid;
}
;
create procedure WEBFINGER_WEBID_GET (in mail varchar)
{
declare webid, domain, host_info, xrd, template, url any;
declare xt, xd, tmpcert any;
if (mail is null)
return null;
declare exit handler for sqlstate '*'
{
-- connection error or parse error
return null;
};
domain := subseq (mail, position ('@', mail));
host_info := http_get (sprintf ('http://%s/.well-known/host-meta', domain));
xd := xtree_doc (host_info);
template := cast (xpath_eval ('/XRD/Link[@rel="lrdd"]/@template', xd) as varchar);
url := replace (template, '{uri}', 'acct:' || mail);
xrd := http_get (url);
xd := xtree_doc (xrd);
xt := xpath_eval ('/XRD/Property[@type="webid"]/@href', xd, 0);
foreach (any x in xt) do
{
return cast (x as varchar);
}
return null;
}
;
create procedure param_set (inout params any, in name varchar, in value varchar)
{
declare pos int;
pos := position (name, params);
if (pos)
{
params [pos] := value;
return;
}
params := vector_concat (params, vector (name, value));
return;
}
;
create procedure html_title ()
{
return 'X.509 Certificate Generator';
}
;
create procedure
BLOG_MESSAGE (in uid int, in content any, in postid varchar, in tms datetime, in title varchar)
{
declare res BLOG.DBA."MTWeblogPost";
res := new BLOG.DBA."MTWeblogPost" ();
res.userid := uid;
res.description := blob_to_string (content);
res.author := (select U_E_MAIL from "DB"."DBA"."SYS_USERS" where U_NAME = uid);
res.dateCreated := tms;
res.mt_allow_pings := 0;
res.mt_allow_comments := 0;
res.postid := postid;
res.title := title;
return res;
}
;
create procedure redirect (in u any)
{
http_header (sprintf ('Location: %s\r\n', u));
}
;
create procedure tab_class (in curr any, in var any)
{
if (curr = var)
http ('class="current"');
}
;
create procedure tab_style (in curr any, in var any)
{
if (curr = var)
return;
http ('style="display: none;"');
}
;
create procedure tag (in fp any, in w any, in dgst any := 'MD5', in fmt any := 'json')
{
declare x, u, pref any;
u := '';
if (w not like 'http%/about/id/entity/%')
{
w := sprintf ('http://%{WSHost}s/c/%s', WS..CURI_MAKE_CURI (w));
u := sprintf ('&uri=%U', w);
}
u := sprintf ('&http=%{WSHost}s');
x := hex2bin (lower (replace (fp, ':', '')));
x := encode_base64url (cast (x as varchar));
if (fmt <> 'sparql')
pref := 'ID Claim: ';
else
pref := '';
return sprintf ('%sdi:%s;%s?hashtag=webid%s', pref, lower (dgst), x, u);
}
;
create procedure tag_old (in fp any, in w any, in dgst any := 'MD5')
{
if (w like 'http%/about/id/entity/%')
w := sprintf ('http://%{WSHost}s/c/%s', WS..CURI_MAKE_CURI (w));
return sprintf ('#X509Cert Fingerprint:%s #%s ; Subject Alt. Name:%s .', replace (fp, ':', ''), upper (dgst), w);
--return sprintf ('Fingerprint:%s Subject Alt. Name (SAN):%s . #WebID', fp, w);
--return sprintf ('#Self #X509Certificate #Fingerprint:%s . #WebID', fp);
}
;
create procedure MAIL_TEXT (in name varchar, in cert any)
{
declare str varchar;
str := DB.DBA.MIME_BODY (
vector (
DB.DBA.MIME_PART ('text/html', null, null, 'The attached is your certificate.
'),
DB.DBA.MIME_PART ('application/octet-stream', 'attachment; filename=' || name, 'base64', cast (cert as varchar))
)
);
str := 'Subject: x.509 certificate\r\n' || str;
return str;
}
;
create procedure remove_frag (in uri any)
{
declare h any;
h := WS.WS.PARSE_URI (uri);
h [5] := '';
uri := WS.WS.VFS_URI_COMPOSE (h);
return uri;
}
;
create procedure microdata (in w any, in m any, in e any)
{
return sprintf ('
', w, e, m);
};
create procedure rdfa (in w any, in m any, in e any)
{
return sprintf (
'
My RSA Public Keys
Modulus (hexadecimal)
%V
Exponent (decimal)
%d
', w, m, e);
};
create procedure ld_json (in w any, in m any, in e any, in idn any)
{
return sprintf (
'
{ "@": [
{ "@": "%s",
"a" : [ "http://xmlns.com/foaf/0.1/Person" ] ,
"http://www.w3.org/ns/auth/cert#key" : [ "%s" ] } ,
{ "@": "%s",
"a" : [ "http://www.w3.org/ns/auth/cert#RSAPublicKey" ] ,
"http://www.w3.org/ns/auth/cert#modulus" : [ { "@literal" : "%s" , "@datatype" : "http://www.w3.org/2001/XMLSchema#hexBinary" } ] ,
"http://www.w3.org/ns/auth/cert#exponent" : [ { "@literal" : "%d" , "@datatype" : "http://www.w3.org/2001/XMLSchema#int" } ] }
] }
', w, idn, idn, m, e);
};
create procedure hcard (in cert any, in webid any, in name any, in mail any, in cid int, in fp varchar, in dgst varchar)
{
declare di varchar;
-- Public Key Ref
di := tag (fp, webid, dgst);
return sprintf ('', webid, name, mail, mail, xenc_X509_certificate_serialize (cert), di);
}
;
create procedure hasWebID ()
{
declare agent, certificate any;
if (not is_https_ctx ())
return 0;
certificate := client_attr ('client_certificate');
if (not certificate) return 0;
agent := DB.DBA.FOAF_SSL_WEBID_GET (certificate);
if (isnull (agent))
return 0;
return 1;
};
create procedure make_qr_code (in data_to_qrcode any, in src_width int := 120, in src_height int := 120, in qr_scale int := 3)
{
declare qrcode_bytes, mixed_content, content varchar;
declare qrcode any;
if (__proc_exists ('QRcode encodeString8bit', 2) is null)
return null;
declare exit handler for sqlstate '*' { return null; };
content := "IM CreateImageBlob" (src_width, src_height, 'white', 'jpg');
qrcode := "QRcode encodeString8bit" (data_to_qrcode);
qrcode_bytes := aref_set_0 (qrcode, 0);
mixed_content := "IM PasteQRcode" (qrcode_bytes, qrcode[1], qrcode[2], qr_scale, qr_scale + 2, 0, 0, cast (content as varchar), length (content));
mixed_content := encode_base64 (cast (mixed_content as varchar));
mixed_content := replace (mixed_content, '\r\n', '');
return mixed_content;
}
;
create procedure "cert" (in "id" int) __SOAP_HTTP 'application/x-x509-user-cert'
{
for select C_CERT from CERT..CERTIFICATES where C_ID = "id" do
http (C_CERT);
return '';
}
;
create procedure "key" (in "id" int) __SOAP_HTTP 'text/plain'
{
declare accept any;
accept := http_request_header_full (http_request_header (), 'Accept', 'text/plain');
--dbg_obj_print_vars (accept);
for select C_CERT from CERT..CERTIFICATES where C_ID = "id" do
{
declare k any;
k := xenc_key_create_cert (null, C_CERT, 'X.509', 3);
if (strstr (accept, 'application/x-ssh-key') is not null)
http (xenc_pubkey_ssh_export (k));
else if (strstr (accept, 'application/x-der-key') is not null)
http (xenc_pubkey_DER_export (k));
else if (strstr (accept, 'text/x-der-key') is not null)
http (encode_base64 (cast (xenc_pubkey_DER_export (k) as varchar)));
else if (strstr (accept, 'text/plain') is not null)
http (xenc_pubkey_PEM_export (k));
else if (strstr (accept, 'text/html') is not null or strstr (accept, '*/*') is not null)
{
http_status_set (303);
http_header (http_header_get () || sprintf ('Location: /describe/?url=http://%{WSHost}s/certgen/key/%d\r\n', "id"));
return '';
}
else
{
declare qr, path, params, lines any;
qr := sprintf ('DESCRIBE ', "id");
http_header ('');
path := vector ('sparql');
params := vector ('query', qr);
lines := http_request_header ();
WS.WS."/!sparql/" (path, params, lines);
return '';
}
http_header (sprintf ('Content-Type: %s\r\n', accept));
xenc_key_remove (k);
}
return '';
}
;
create trigger CERTIFICATES_AI after insert on CERTIFICATES referencing new as N
{
declare md5, sha1, b64, v32, dval varchar;
dval := replace (get_certificate_info (6, N.C_CERT, 1, null, 'md5'), ':', '');
b64 := subseq (hex2bin (dval), 0, 32);
md5 := encode_base64url (cast (b64 as varchar));
dval := replace (get_certificate_info (6, N.C_CERT, 1, null, 'sha1'), ':', '');
b64 := subseq (hex2bin (dval), 0, 32);
sha1 := encode_base64url (cast (b64 as varchar));
set triggers off;
update CERTIFICATES set C_MD5 = md5, C_SHA1 = sha1 where C_ID = N.C_ID;
set triggers on;
}
;
create trigger CERTIFICATES_AU after update on CERTIFICATES referencing old as O, new as N
{
declare md5, sha1, b64, v32, dval varchar;
dval := replace (get_certificate_info (6, N.C_CERT, 1, null, 'md5'), ':', '');
if (dval is null)
return;
b64 := subseq (hex2bin (dval), 0, 32);
md5 := encode_base64url (cast (b64 as varchar));
dval := replace (get_certificate_info (6, N.C_CERT, 1, null, 'sha1'), ':', '');
b64 := subseq (hex2bin (dval), 0, 32);
sha1 := encode_base64url (cast (b64 as varchar));
set triggers off;
update CERTIFICATES set C_MD5 = md5, C_SHA1 = sha1 where C_ID = N.C_ID;
set triggers on;
}
;
update CERTIFICATES set C_CERT = C_CERT where C_MD5 is null;
create procedure "di" () __SOAP_HTTP 'application/x-x509-user-cert'
{
declare path, dgst, val, cert, accept, cert_id any;
path := http_physical_path ();
path := split_and_decode (path, 0, '\0\0/');
--dbg_obj_print (current_proc_name ());
if (length (path) < 6)
return NULL;
dgst := path[4];
val := path[5];
accept := http_request_header_full (http_request_header (), 'Accept', 'text/plain');
if (strstr (accept, 'application/x-x509-user-cert') is null)
{
if (dgst = 'md5')
cert_id := (select C_ID from CERT..CERTIFICATES where C_MD5 = val);
else if (dgst = 'sha1')
cert_id := (select C_ID from CERT..CERTIFICATES where C_SHA1 = val);
else
signal ('42000', 'Digest not supported');
--http_status_set (303);
--http_header (sprintf ('Location: http://%{WSHost}s/certgen/key/%d\r\n', cert_id));
CERT.DBA."key" (cert_id);
return '';
}
--dbg_obj_print_vars (dgst, val);
if (dgst = 'md5')
cert := (select C_CERT from CERT..CERTIFICATES where C_MD5 = val);
else if (dgst = 'sha1')
cert := (select C_CERT from CERT..CERTIFICATES where C_SHA1 = val);
else
signal ('42000', 'Digest not supported');
http (cert);
return '';
}
;
create procedure CERT_INIT ()
{
if (exists (select 1 from DB.DBA.SYS_USERS where U_NAME = 'CERTGEN'))
return;
DB.DBA.USER_CREATE ('CERTGEN', uuid(), vector ('DISABLED', 1, 'LOGIN_QUALIFIER', 'CERT'));
};
CERT_INIT ();
DB.DBA.VHOST_REMOVE (lpath=>'/certgen/cert');
DB.DBA.VHOST_DEFINE (lpath=>'/certgen/cert', ppath=>'/SOAP/Http/cert', soap_user=>'CERTGEN', opts=>vector ('url_rewrite', 'certgen_certs_list1'));
DB.DBA.VHOST_REMOVE (lpath=>'/certgen/key');
DB.DBA.VHOST_DEFINE (lpath=>'/certgen/key', ppath=>'/SOAP/Http/key', soap_user=>'CERTGEN', opts=>vector ('url_rewrite', 'certgen_certs_list1'));
DB.DBA.VHOST_REMOVE (lpath=>'/.well-known/di');
DB.DBA.VHOST_DEFINE (lpath=>'/.well-known/di', ppath=>'/SOAP/Http/di', soap_user=>'CERTGEN');
DB.DBA.URLREWRITE_CREATE_RULELIST ('certgen_certs_list1', 1, vector ('certgen_cert_rule1'));
DB.DBA.URLREWRITE_CREATE_REGEX_RULE ('certgen_cert_rule1', 1,
'/certgen/([^/]*)/([^/]*)\x24',
vector('m', 'id'), 1,
'/certgen/%s?id=%s', vector('m', 'id'),
null,
null,
2);
grant execute on CERT.DBA."cert" to CERTGEN;
grant execute on CERT.DBA."key" to CERTGEN;
grant execute on CERT.DBA."di" to CERTGEN;
¶ certgen_html/caselect.vspß m webid and pwebid <> w)
webid := w := pwebid;
?>
Select signer of the certificate
¶ certgen_html/cert.cssß mbody
{
font-family: Verdana,Helvetica,sans-serif;
//width:70%;
}
h1
{
font-size: 18px;
}
fieldset
{
//border-radius: 20px;
//background-color: honeydew;
font-size: 14px;
border-width: 1px;
}
input.btn
{
margin-top: 10px;
}
input.txt
{
border-width: 1px;
width: 400px;
}
input.url
{
border-width: 1px;
}
/* area controlled by navigation tabs */
#navarea {
background-color: white;
width: 100%;
margin: 0;
padding: 0;
}
#navarea li {
font-size: 80%;
font-family: Verdana, Arial, Helvetica, sans-serif;
line-height: 175%;
}
/* navigation tabs */
#navlist {
padding: 3px;
margin-left: 0;
padding-bottom: 3px;
border-bottom: 1px solid #778 }
#navlist li {
list-style: none;
margin: 0;
display: inline;
line-height: 120% }
#navlist li a {
padding: 3px 0.5em;
margin-left: 3px;
border: 1px solid #778;
border-bottom: none;
background: #DDE;
text-decoration: none;
line-height: 120% }
#navlist li a:link { color: #448; }
#navlist li a:visited { color: #667; }
#navlist li a:hover {
color: #000;
background: #AAE;
border-color: #227;
border-bottom: none }
#navlist li a.current {
background: white;
border-bottom: none;
line-height: 120%;
padding-bottom: 5px; }
#qrcode {
float: right;
clear: right;
margin-right: 20px; }
.note { color: red; }
.log { color: green; }
¶ certgen_html/cert.jsß
–/*
* $Id: cert.js,v 1.8 2012/02/16 13:49:20 mitko Exp $
*
* Copyright (C) 2005-2010 OpenLink Software
*
* See LICENSE file for details.
*/
function go_back (page)
{
document.forms[0].action = page;
document.forms[0].submit ();
}
function fld_check_empty (fld, btn, name)
{
var btn = document.getElementById ('btn');
if (fld.value.length == 0)
{
btn.disabled = true;
alert ("The " + name + " field must not be empty");
}
else
{
btn.disabled = false;
}
}
function kgen_disable ()
{
var c = document.getElementById ('kgen');
if (c)
{
var k = document.getElementById ('pubkey');
var b = document.getElementById ('down');
k.disabled = true;
b.disabled = true;
}
}
function kgen_toggle ()
{
var c = document.getElementById ('kgen');
var k = document.getElementById ('pubkey');
var b = document.getElementById ('down');
if (c.checked == true)
{
k.disabled = false;
Show ('span_pubkey');
b.value = 'Send certificate request';
}
else
{
k.disabled = true;
Hide ('span_pubkey');
b.value = 'Download';
}
}
/* -- Tabbed interface support -- */
function Show(objid)
{
var obj = document.getElementById(objid);
obj.style.display="";
obj.visible = true;
}
function Hide(objid)
{
var obj = document.getElementById(objid);
obj.style.display="none";
obj.visible = false;
}
function toggle_tab(div_id)
{
var obj = document.getElementById('tab_'+div_id);
var ul_obj = document.getElementById('navlist');
var nodeList = returnListOfNodes(ul_obj.childNodes);
for(var i=0; i < nodeList.length;i++)
{
returnListOfNodes(nodeList[i].childNodes)[0].className = "";
};
obj.className = "current";
var ContentDivs = Array(
document.getElementById('sparql'),
document.getElementById('pem'),
document.getElementById('ld'),
document.getElementById('html'),
document.getElementById('md'),
document.getElementById('diuri'),
document.getElementById('hcard'),
document.getElementById('oauth'),
document.getElementById('atom')
);
for (var i = 0; i < ContentDivs.length; i++)
{
if (ContentDivs[i].id == div_id && ContentDivs[i].style.display == 'none')
Show(ContentDivs[i].id);
else if (ContentDivs[i].id != div_id && ContentDivs[i].style.display != 'none')
Hide(ContentDivs[i].id);
};
}
function returnListOfNodes(nodeList)
{
var list = new Object();
var x = 0;
for (var i = 0; i < nodeList.length; i++)
{
if(nodeList[i].nodeType == 1)
{
list[x++] = nodeList[i];
}
}
list.length = x--;
return list;
}
/* -- End: Tabbed interface support -- */
¶ certgen_html/certgen.vspß |«
'openid.mode' and params[i] <> 'Content')
auri := auri || sprintf ('&%U=%U', params[i], charset_recode (params[i+1], 'UTF-8', '_WIDE_'));
}
rc := http_get (auri);
rcarr := split_and_decode (rc, 0, '\0\0\n');
if (position ('is_valid:true', rcarr) <= 0)
{
openid_sig := null;
error_message := 'The OpenID signature verification failed.';
goto error;
}
axarr := CERT..openid_parse_ax (params);
-- dbg_obj_print (axarr);
if (axarr is null) axarr := vector ();
name := coalesce (get_keyword ('fullname', axarr), get_keyword ('fullname1', axarr));
fname := get_keyword ('firstname', axarr);
lname := get_keyword ('lastname', axarr);
email := coalesce ( get_keyword ('email', axarr), get_keyword ('email1', axarr));
if (name is null and fname is not null and lname is not null)
name := fname || ' ' || lname;
}
else -- 1.0 approach
{
openid_key_name := {?'sid'};
k := (select SS_KEY from CERT..OPENID_SESSIONS where SS_KEY_NAME = openid_key_name);
-- dbg_obj_print_vars (openid_key_name, k);
rc := openid..check_signature (http_request_get ('QUERY_STRING')|| sprintf ('&mac_key=%U', cast (k as varchar)));
if (rc = 0)
{
openid_sig := null;
error_message := 'The OpenID signature verification failed.';
goto error;
}
openid_key := cast (k as varchar);
openid_sig := http_request_get ('QUERY_STRING');
--name := {?'openid.sreg.fullname'};
--email := {?'openid.sreg.email'};
}
-- last chance we try sreg
if (not length (name)) name := {?'openid.sreg.fullname'};
if (not length (email)) email := {?'openid.sreg.email'};
CERT..param_set (params, 'cn', name);
CERT..param_set (params, 'email', email);
if (length (email) > 0)
{
webid := CERT..register_trusted_email (email);
CERT..param_set (params, 'webid', webid);
prx := 0;
proxy_iri := DB.DBA.RDF_PROXY_ENTITY_IRI (CERT..remove_frag (webid));
}
if (length (email) = 0)
{
openid_sig := null;
error_message := 'The e-mail address cannot be fetched';
goto error;
}
}
if (get_keyword ('openid.mode', params) = 'cancel')
{
openid_sig := null;
error_message := 'The OpenID identity verification canceled.';
goto error;
}
if ({?'fetch'} is not null and length ({?'openid_url'}))
{
declare url, ret, cnt, oi_srv, oi_delegate, oi_ident, this_page, xt, hdr, host, oi_mode any;
declare setup_url, oi_handle, trust_root, oi_sig, oi_signed, oi_key varchar;
declare ses, flds, check_immediate, disco any;
host := http_request_header (lines, 'Host');
openid_key_name := xenc_rand_bytes (8,1);
this_page := 'http://' || host || http_path () || sprintf ('?sid=%U', openid_key_name);
for (declare i int, i := 0; i < length (params); i := i + 2)
{
if (params[i] <> 'fetch' and params[i] <> 'Content')
this_page := this_page || sprintf ('&%U=%U', params[i], params[i+1]);
}
trust_root := 'http://' || host;
oi_ident := {?'openid_url'};
if (oi_ident is not null)
{
url := trim(oi_ident);
declare exit handler for sqlstate '*'
{
error_message := 'The URL cannot be retrieved';
goto error;
};
if (not length (url) or url not like 'http%://%')
{
error_message := 'Invalid URL';
goto error;
}
disco := cert..openid_discover (url);
oi_ident := disco[3];
oi_srv := disco[1];
if (disco[0] = 2)
{
-- OpenID2
url := concat (oi_srv,
'?openid.ns=http://specs.openid.net/auth/2.0',
'&openid.mode=checkid_setup',
'&openid.claimed_id=http://specs.openid.net/auth/2.0/identifier_select',
'&openid.identity=http://specs.openid.net/auth/2.0/identifier_select',
sprintf ('&openid.return_to=%U', this_page));
if (disco[2] = 'http://openid.net/srv/ax/1.0') -- ax supported
{
url := concat (url, '&openid.ns.ax=http://openid.net/srv/ax/1.0',
'&openid.ax.mode=fetch_request',
'&openid.ax.required=firstname,lastname,email',
'&openid.ax.if_available=fullname,fullname1,email1',
'&openid.ax.type.firstname=http://axschema.org/namePerson/first', -- schema supported by Y! and Google
'&openid.ax.type.lastname=http://axschema.org/namePerson/last',
'&openid.ax.type.fullname=http://axschema.org/namePerson',
'&openid.ax.type.email=http://axschema.org/contact/email',
'&openid.ax.type.fullname1=http://schema.openid.net/namePerson', -- the other schema
'&openid.ax.type.email1=http://schema.openid.net/contact/email'
);
}
else -- we try sreg
{
url := concat (url,'&openid.sreg.optional=email,fullname');
}
http_status_set (303);
http_header ('Location:' || url || '\r\n');
return;
}
if (oi_srv is null)
{
error_message := 'The OpenID server cannot be located';
goto error;
}
--dbg_obj_print_vars (oi_srv, oi_delegate);
oi_handle := null;
oi_key := '';
check_immediate := sprintf ('%s?openid.mode=associate', oi_srv);
cnt := http_client (url=>check_immediate);
--dbg_obj_print_vars (check_immediate, cnt);
cnt := split_and_decode (cnt, 0, '\0\0\x0A:');
oi_handle := get_keyword ('assoc_handle', cnt, null);
oi_key := get_keyword ('mac_key', cnt, '');
insert soft CERT..OPENID_SESSIONS (SS_HANDLE, SS_KEY, SS_KEY_TYPE, SS_EXPIRY, SS_KEY_NAME)
values (oi_handle, oi_key, 'RAW', dateadd ('hour', 1, now()), openid_key_name);
openid_key := oi_key;
check_immediate :=
sprintf ('%s?openid.mode=checkid_setup&openid.identity=%U&openid.return_to=%U&openid.trust_root=%U',
oi_srv, oi_ident, this_page, trust_root);
if (length (oi_handle))
check_immediate := check_immediate || sprintf ('&openid.assoc_handle=%U', oi_handle);
check_immediate := check_immediate || sprintf ('&openid.sreg.optional=%U', 'email,fullname');
http_status_set (302);
http_header (sprintf ('Location: %s\r\n', check_immediate));
return;
}
error:;
}
-------------------------------
-- Mail verification
-------------------------------
if ({?'chk'} is not null and length ({?'mv'}) and length ({?'email'}))
{
declare cb any;
cb := sprintf ('http://%{WSHost}s/certgen/mvcb.vsp?email=%U', {?'email'});
http_status_set (302);
http_header (sprintf ('Location: %s?mbox=%U&cb=%U\r\n', {?'mv'}, {?'email'}, cb));
return;
}
?>
Virtuoso X.509 Certificate Generator
Certificate Generator
We can associate your YouID with one of the common Social Web Services .
Once a certificate has been generated, a Tweet , or Status Update containing a digest
of your certificate will be posted in the service you chose to associate it with.
The post will serve as a proof of ownership when you log in using YouID , so please do
not delete it unless you no longer want to use the YouID we made for you.
Click one of the buttons below to authenticate using the service. If you are using
this YouID service for the first time, the Social Web Service will ask you to give
permission to access your information. This is necessary to generate the certificate
and the post validating it.
Use one of the following drop-down options for profile data access:
Use ATOM publishing protocol to create a blog post to act as proof of control. Use your blog, or ATOM publishing protocol endpoint URL.
Your Information
This information will be encoded within the certificate. If email address is left empty, S/MIME mail signing options will not be available. It is okay to just use the default options.
Certificate Parameters
The certificate may have many different uses. WebID can be used for authenticating with web sites.
WebID + S/MIME may be used for both authentication and signing/encrypting of emails.
Certificate cipher and strength are also important: longer keys are more difficult to produce
and crack, and therefore are safer.
If you are unsure, just leave the values as is.
Make a post containing the certificate digest that will be used as verification.
Your certificate data in various text formats.
Format:
PEM
XHTML+RDFa
HTML+Microdata
HTML+hCard
JSON-LD
Data:
Post in blog
You can download the local Certificate Authority certificate for verification purposes.
Download CA Certificate
Copyright © 2011-2012 OpenLink Software
Generic error
Authentication with the identity provider failed.
¶ certgen_html/certgen_svc.vspß [j '')
{
san := san || ', email:' || email;
san := ltrim (san, ', ');
}
if (key_name = '')
{
key_name := sprintf ('cert_gen_key_%d', sequence_next ('cert_gen_key_seq'));
}
-- dbg_printf ('gen_cert: san: %s, key_name: ', san);
-- dbg_obj_print (key_name);
CERT..generate_key (key_name, key_len);
CERT..gen_cert_parms (ext_key_usage, key_usage, ca); -- Side effects warning - inout params
CERT..sign_and_make_cert (ca_key, key_name, cn, o, c, st, email, ca, san, ext_key_usage, key_usage, cipher);
cid := CERT..save_cert (key_name);
declare cert_info varchar;
cert_info := CERT..get_cert_info(key_name, webid, digest_type);
CERT..set_json_out_hdr ();
declare ret_val varchar;
ret_val := sprintf ('{"key_name":"%s","cn":"%s","o":"%s","email":"%s","san":"%s","cert_info": %s}',
key_name, cn, o, email, san, cert_info);
-- dbg_printf ('%s', ret_val);
http (ret_val);
-- dbg_printf ('gen_cert exiting');
return cid;
}
-- set by URI-rewriter /certgen/gen_cert
if ({?'gen_ss_cert'} is not null)
{
if (0 = length (webid))
{
error_text := 'Missing required parameter (webid)';
goto error_exit;
}
if (0 = length (cn))
{
error_text := 'Missing name';
goto error_exit;
}
san := 'URI:' || webid;
if (email is not null and email <> '')
{
san := san || ', email:' || email;
san := ltrim (san, ', ');
}
if (key_name = '')
{
key_name := sprintf ('cert_gen_key_%d', sequence_next ('cert_gen_key_seq'));
}
-- dbg_printf ('gen_ss_cert: san: %s', san);
CERT..generate_key (key_name, key_len);
CERT..gen_cert_parms (ext_key_usage, key_usage, ca); -- Side effects warning - inout params
CERT..self_sign_and_make_cert (key_name, cn, o, c, st, email, ca, san, ext_key_usage, key_usage, cipher);
cid := CERT..save_cert (key_name);
declare cert_info varchar;
cert_info := CERT..get_cert_info(key_name, webid, digest_type);
CERT..set_json_out_hdr ();
declare ret_val varchar;
ret_val := sprintf ('{"key_name":"%s","cn":"%s","o":"%s","email":"%s","san":"%s","cert_info": %s}',
key_name, cn, o, email, san, cert_info);
-- dbg_printf ('%s', ret_val);
http (ret_val);
-- dbg_printf ('gen_ss_cert exiting');
return cid;
}
if ({?'get_oauth_post_data'} is not null)
{
if ({?'webid'} is null) {
error_text := 'Missing required parameter (webid)';
goto error_exit;
}
if ({?'digest_type'} is null) {
error_text := 'Missing required parameter (digest_type)';
goto error_exit;
}
if ({?'key_name'} is null) {
error_text := 'Missing required parameter (key_name)';
goto error_exit;
}
webid := {?'webid'};
CERT..set_json_out_hdr ();
http (CERT..get_cert_info (key_name, webid, digest_type));
return;
}
if ({?'post_oauth'} is not null)
{
declare post_content varchar;
post_content := {?'post_content'};
if (post_content is null)
{
error_text := 'Missing required parameter (post_content)';
goto error_exit;
}
declare tw_sid, li_sid, fb_tok varchar;
tw_sid := {?'tw_sid'};
li_sid := {?'li_sid'};
fb_tok := {?'fb_tok'};
if (tw_sid is null and li_sid is null and fb_tok is null)
{
error_text := 'Missing required parameter (sid).';
goto error_exit;
}
declare exit handler for sqlstate '*'
{
error_text := __SQL_MESSAGE;
goto error_exit;
};
declare auth_token varchar;
declare auth varchar;
declare res varchar;
declare header varchar;
if (length (tw_sid)) -- twitter
{
declare tw_id varchar;
declare tw_url varchar;
declare post varchar;
post := sprintf ('status=%U', post_content); -- comes encoded from jQuery
auth_token := ODS.ODS_API.get_oauth_tok ('Twitter API');
-- dbg_printf ('auth_token: %s', auth_token);
auth := OAUTH..signed_request_header ('POST',
'https://api.twitter.com/1/statuses/update.xml',
post,
auth_token, '', tw_sid, 0);
tw_url := sprintf ('https://api.twitter.com/1/statuses/update.xml');
res := http_get (tw_url, header, 'POST', auth, post);
-- dbg_printf ('%s', res);
tw_id := cast (xpath_eval ('/status/id/text()', xtree_doc (res)) as varchar);
if (tw_id is not null)
{
tw_url := sprintf ('https://api.twitter.com/1/favorites/create/%s.xml', tw_id);
auth := OAUTH..signed_request_header ('POST', tw_url, '', auth_token, '', tw_sid, 0);
res := http_get (tw_url, header, 'POST', auth, null);
-- dbg_obj_print_vars (res, header);
OAUTH..session_terminate (tw_sid);
}
else
{
error_text := cast (xpath_eval ('/hash/error/text()', xtree_doc (res)) as varchar);
goto error_exit;
}
}
else if (length (li_sid))
{
auth_token := ODS.ODS_API.get_oauth_tok ('LinkedIn API');
auth := OAUTH..sign_request ('POST', 'http://api.linkedin.com/v1/people/~/shares', '', auth_token, li_sid, 1);
res := http_get ('http://api.linkedin.com/v1/people/~/shares?' || auth, header, 'POST', 'Content-Type: text/xml',
sprintf ('%V anyone
',
post_content));
OAUTH..session_terminate (li_sid);
}
else if (length (fb_tok))
{
declare fb_nick varchar;
fb_nick := {?'fb_nick'};
if (fb_nick is null) {
error_text := 'Missing required parameter (fb_nick)';
goto error_exit;
}
res := http_get (sprintf ('https://graph.facebook.com/%U/feed', fb_nick),
header, 'POST', null, sprintf ('access_token=%U&message=%U', fb_tok, post_content));
fb_tok := null;
CERT..param_set (params, 'fb_tok', null);
}
if ({?'prx'} = '1') -- Proxy involves sponging
{
declare sql_state, msg, gr, sparql_ins_stmt varchar;
-- dbg_printf ('Invoking sponger');
gr := CERT..remove_frag (webid_plain);
sparql_ins_stmt := CERT..get_cert_info (key_name, webid, digest_type, 'sparql');
sql_state := '00000';
exec (sprintf ('sparql define get:soft "add" define get:refresh "0" select count(*) from <%S> where { ?s ?p ?o }', webid), sql_state, msg);
exec ('sparql define input:default-graph-uri <' || webid || '> ' || sparql_ins_stmt, sql_state, msg);
exec ('sparql define input:default-graph-uri <' || gr || '> ' || sparql_ins_stmt, sql_state, msg);
}
return;
}
if ({?'get_cert_dump'} is not null)
{
declare fmt varchar;
fmt := {?'format'};
if (key_name is null)
{
error_text := 'Missing required parameter (key_name)';
goto error_exit;
}
cid := CERT..get_cid (key_name);
if (webid is null)
{
error_text := 'Missing required parameter (webid)';
}
if (fmt is null)
{
error_text := 'Missing required parameter (format)';
goto error_exit;
}
if (digest_type is null)
{
error_text := 'Missing required parameter (digest_type)';
goto error_exit;
}
declare cert_info any;
cert_info := CERT..get_cert_info (key_name, webid, digest_type, 'vector');
-- dbg_obj_print (cert_info);
declare exponent,fingerprint,modulus varchar;
exponent := get_keyword ('exponent', cert_info);
fingerprint := get_keyword ('fingerprint', cert_info);
modulus := get_keyword ('modulus', cert_info);
if (fmt = 'pem')
return;
if (fmt = 'rdfa')
{
CERT..set_json_out_hdr();
declare newmod varchar;
newmod := CERT..mangle_modulus (modulus);
http (sprintf ('{"fmt":"%s","data":"%U"}',
fmt, CERT..rdfa (webid, newmod, exponent)));
return;
}
else if (fmt = 'microdata')
{
CERT..set_json_out_hdr();
declare newmod varchar;
newmod := CERT..mangle_modulus (modulus);
http (sprintf ('{"fmt":"%s","data":"%U"}',
fmt, CERT..microdata (webid, newmod, exponent)));
return;
}
else if (fmt = 'hcard')
{
CERT..set_json_out_hdr();
http (sprintf ('{"fmt":"%s","data":"%U"}',
fmt, CERT..hcard (key_name,
webid,
cn,
email,
cid,
fingerprint,
digest_type)));
return;
}
else if (fmt = 'jsonld')
{
CERT..set_json_out_hdr();
declare idn varchar;
idn := CERT..remove_frag(webid) || '#' || fingerprint;
http (sprintf ('{"fmt":"%s","data":"%U"}',
fmt, CERT..ld_json (webid, modulus, exponent, idn)));
return;
}
else
error_text := sprintf ('Unrecognized format (%s)', fmt);
goto error_exit;
}
if ({?'login_atom'} is not null)
{
declare ep, uid, pwd, post_id, post_url varchar;
declare res any;
ep := {?'ep'};
post_id := '';
if (ep is null)
{
error_text := '';
}
uid := {?'uid'};
pwd := {?'pwd'};
--dbg_obj_print_vars (ep, uid, pwd);
res := CERT..handle_atom_endpoint (ep, uid, pwd);
CERT..set_json_out_hdr ();
post_id := res[1];
post_url := res[2];
if (post_id is null or post_id = '')
{
error_text := 'Can not create post entry';
goto error_exit;
}
if (key_name = '')
key_name := sprintf ('cert_gen_key_%d', sequence_next ('cert_gen_key_seq'));
http (sprintf ('{"endpoint": "%s","post_id":"%s", "webid": "%s", "name":"%s", "email":"%s", "webid_proxy":"%s", "key_name":"%s" }',
res[0], post_id, post_url, coalesce (res[4], ''), coalesce (res[3], ''), DB.DBA.RDF_PROXY_ENTITY_IRI (CERT..remove_frag (post_url)), key_name));
return;
}
if ({?'browserid_login'} is not null)
{
-- dbg_printf ('in login_browserid');
declare digest, id, ep, h, name, assertion, audience varchar;
declare res any;
assertion := {?'assertion'};
if (assertion is null)
{
error_text := 'Missing required parameter (assertion)';
goto error_exit;
}
-- dbg_printf ('assertion: %s', assertion);
h := http_request_header (lines, 'Host', null, null);
audience := case when is_https_ctx() then 'https://' else 'http://' end || h;
res := http_get ('https://browserid.org/verify', null, 'POST', null, sprintf ('assertion=%U&audience=%U', assertion, audience));
-- dbg_obj_print (res);
res := json_parse (res);
email := get_keyword ('email', res);
name := subseq (email, 0, strchr (email, '@'));
digest := sha1_digest (email);
id := sprintf ('http://%{URIQADefaultHost}s/mv/data/') || bin2hex (cast (decode_base64 (digest) as varbinary));
webid := id || '#this';
ep := sprintf ('http://%{URIQADefaultHost}s/sparql-auth/');
sparql prefix foaf: insert into graph iri ('http://localhost/mv')
{
`iri (?:webid)` a foaf:Person .
`iri (?:id)` a foaf:Document .
`iri (?:id)` .
`iri(?:ep)` .
`iri (?:id)` foaf:primaryTopic `iri(?:webid)` .
`iri(?:webid)` foaf:mbox_sha1sum ?:digest .
};
CERT..set_json_out_hdr();
http (sprintf ('{"webid":"%U","email":"%U","cn":"%U"}', webid, email, name));
-- dbg_printf ('login_browserid: webid: %s, email: %s, cn: %s', webid, email, name);
return;
}
if ({?'save_sparql'} is not null)
{
declare ep, uid, pwd, pingback varchar;
ep := {?'ep'};
uid := {?'uid'};
pwd := {?'pwd'};
pingback := {?'pingback'};
if (ep is null)
{
error_text := 'Missing required parameter (ep)';
goto error_exit;
}
if (key_name is null)
{
error_text := 'Missing required parameter (key_name)';
goto error_exit;
}
if (webid is null)
{
error_text := 'Missing required parameter (webid)';
goto error_exit;
}
if (digest_type is null)
{
error_text := 'Missing required parameter (digest_type)';
goto error_exit;
}
declare exit handler for sqlstate 'OCG*'
{
error_text := __SQL_MESSAGE;
goto error_exit;
};
declare exit handler for sqlstate 'HTCLI'
{
error_text := 'Could not connect to endpoint. ' || __SQL_MESSAGE;
goto error_exit;
};
CERT..save_cert_sparql (ep, uid, pwd, webid, key_name, digest_type);
if (length (pingback))
{
declare pars, head any;
pars := sprintf ('source=%U&target=%U', webid, webid_plain);
http_client_ext (url=>pingback, headers=>head, http_method=>'POST', body=>pars);
}
return;
}
if ({?'download_cert'} is not null)
{
declare cert_pwd, filename, ret varchar;
declare dl_type varchar;
dl_type := {?'cert_dl_type'};
-- dbg_printf ('dl_type: %s, key_name: %s', dl_type, key_name);
if (length ({?'cert_pwd'}))
cert_pwd := {?'cert_pwd'};
else if (dl_type in ('pem', 'p12'))
{
error_text := 'Missing required parameter (cert_pwd)';
goto error_exit;
}
else
cert_pwd := '';
if (dl_type = 'ca')
{
ret := decode_base64 (xenc_X509_certificate_serialize ('id_rsa'));
filename := 'ca.crt';
}
else if (dl_type = 'p12')
{
ret := xenc_pkcs12_export (key_name, {?'bname'}, cert_pwd);
if (ret = 0)
{
error_text := 'The browser-side private key can not be exported.';
goto error_exit;
}
filename := {?'bname'} || '.p12';
}
else if (dl_type = 'pem')
{
ret := xenc_pem_export (key_name, 1, 'aes256', cert_pwd);
filename := {?'bname'} || '.pem';
}
else if (dl_type = 'der')
{
ret := decode_base64 (xenc_X509_certificate_serialize (key_name));
filename := {?'bname'} || '.crt';
}
else
signal ('22023', 'Unsupported format');
if (filename[0] = '.'[0])
filename := 'unknown' || filename;
if (length (get_keyword ('email', params)) and length ({?'cert_pwd'}))
{
declare rc, adm_mail varchar;
adm_mail := (select U_E_MAIL from SYS_USERS where U_NAME = 'dav');
rc := smtp_send (null, adm_mail, get_keyword ('email', params),
CERT..MAIL_TEXT (filename, ret));
}
else
{
-- need handler
http_rewrite ();
http_header (sprintf ('Content-Type: application/octet-stream\r\nContent-Disposition: attachment; filename=%s\r\n', filename));
http (ret);
return;
}
return;
}
if ({?'foaf_webfinger_login'} is not null)
{
declare webid_var2, name_var2, email_var2, org_var2 varchar;
declare graph_name varchar;
declare t, p varchar;
t := {?'t'};
p := {?'p'};
-- dbg_printf ('In foaf_webfinger_login: t: %s, p: %s', t, p);
if (t = 'webfinger')
{
webid := CERT..WEBFINGER_WEBID_GET (p);
if (length (webid))
{
p := webid;
}
else
p := null;
-- dbg_obj_print (webid);
}
if (length (p)) -- FOAF lookup
{
graph_name := 'tmp:' || uuid ();
sparql load ?:p into ?:graph_name;
-- dbg_obj_print (graph_name);
for select * from (sparql select * where { graph `iri(?:graph_name)` {
[] foaf:primaryTopic ?webid_var . ?webid_var foaf:name ?name_var .
optional { ?webid_var foaf:mbox ?email_var . }
optional { ?webid_var foaf:workplaceHomepage ?page . }
optional { ?oid foaf:homepage ?page . ?oid dc:title ?org_var . } }}) x do
{
if (email_var is null) email_var := '';
email_var2 := subseq (email_var, position (':', email_var));
email_var2 := coalesce (email_var2, '');
name_var2 := coalesce (name_var, '');
webid_var2 := webid_var;
org_var2 := coalesce (org_var,'');
}
}
-- dbg_obj_print (webid);
-- dbg_obj_print (webid_var);
if (webid_var2 <> 0) webid := webid_var2;
if (not email_var2) email_var2 := '';
if (not name_var2) name_var2 := '';
if (not org_var2) org_var2 := '';
sparql clear graph iri(?:graph_name);
if (webid is null) webid := '';
CERT..set_json_out_hdr();
if (key_name = '')
{
key_name := sprintf ('cert_gen_key_%d', sequence_next ('cert_gen_key_seq'));
}
http (sprintf ('{"webid":"%U","cn":"%V","email":"%U","o":"%U", "key_name":"%s", "webid_proxy":"%U"}', webid, name_var2, email_var2, org_var2, key_name, DB.DBA.RDF_PROXY_ENTITY_IRI (CERT..remove_frag (webid))));
return;
}
if ({?'get_sparql_ep'} is not null)
{
declare sp_res any;
if (webid is null)
{
error_text := 'Missing required parameter (webid)';
goto error_exit;
}
-- dbg_printf ('get_sparql_ep use_proxy: ');
-- dbg_obj_print (use_proxy);
CERT..set_json_out_hdr();
sp_res := CERT..get_sparql_ep (webid_plain, coalesce (use_proxy,0));
http (sprintf ('{"webid":"%U","use_proxy":"%d","sparql_ep":"%U", "pingback_ep":"%U"}',
webid, use_proxy, sp_res [0], coalesce (sp_res[1], '')));
return;
}
-- get certificate serializations
if ({?'cert_serialize'} is not null)
{
declare fmts varchar;
fmts := {?'formats'};
if (fmts is null) {
error_text := 'Missing required parameter (formats)';
goto error_exit;
}
declare cid varchar;
cid := {?'cert_id'};
if (cid is null) {
error_text := 'Missing required parameter (cert_id)';
goto error_exit;
}
-- if (fmts := 'all') {
-- dbg_printf ('all');
-- }
CERT..set_json_out_hdr();
http (sprintf ('{"cert_id": "%d", "ser": %s}',
cid, CERT..serialize_for_json_out (cid, fmts)));
return cid;
}
if ({?'post_atom'} is not null)
{
declare rc any;
rc := CERT..atom_post_edit ({?'endpoint'}, {?'user'}, {?'pass'}, {?'post_id'}, {?'post_content'}, 'WebID');
if ({?'prx'} = '1') -- Proxy involves sponging
{
declare sql_state, msg, gr, sparql_ins_stmt varchar;
-- dbg_printf ('Invoking sponger');
gr := CERT..remove_frag (webid_plain);
sparql_ins_stmt := CERT..get_cert_info (key_name, webid, digest_type, 'sparql');
sql_state := '00000';
exec (sprintf ('sparql define get:soft "add" define get:refresh "0" select count(*) from <%S> where { ?s ?p ?o }', webid), sql_state, msg);
exec ('sparql define input:default-graph-uri <' || webid || '> ' || sparql_ins_stmt, sql_state, msg);
exec ('sparql define input:default-graph-uri <' || gr || '> ' || sparql_ins_stmt, sql_state, msg);
}
return;
}
if ({?'wl_get_info'} is not null)
{
declare tree, access_token, wl_response, digest, id, ep, name any;
access_token := {?'wl_get_info'};
wl_response := http_get (sprintf ('https://apis.live.net/v5.0/me?access_token=%s', access_token));
tree := json_parse (wl_response);
name := get_keyword ('name', tree);
tree := get_keyword ('emails', tree);
email := get_keyword ('preferred', tree);
digest := sha1_digest (email);
id := sprintf ('http://%{URIQADefaultHost}s/mv/data/') || bin2hex (cast (decode_base64 (digest) as varbinary));
webid := id || '#this';
ep := sprintf ('http://%{URIQADefaultHost}s/sparql-auth/');
sparql prefix foaf: insert into graph iri ('http://localhost/mv')
{
`iri (?:webid)` a foaf:Person .
`iri (?:id)` a foaf:Document .
`iri (?:id)` .
`iri(?:ep)` .
`iri (?:id)` foaf:primaryTopic `iri(?:webid)` .
`iri(?:webid)` foaf:mbox_sha1sum ?:digest .
};
CERT..set_json_out_hdr();
--dbg_obj_print_vars (webid, email, name);
http (sprintf ('{"webid":"%U","email":"%U","cn":"%U"}', webid, email, name));
return;
}
error_text := 'Unrecognized request'; -- catch-all
error_exit:
-- dbg_printf ('certgen_svc.vsp: error:%s', error_text);
http_status_set(400);
?>
400 Bad Request
Bad Request
= error_text ?>
¶ certgen_html/convert.vspß ·
Certificate converter
Select File:
Select File Type:
PEM
PKCS#12
DER
Password for unlocking (if applicable):
Select Output Format:
PKCS#12
PEM
DER
¶ certgen_html/del.vspß ³
Virtuoso X.509 Certificate Generator
Certificate Generator
?key ;
?:cert_fingerprint . }}) x do
{
delete from DB.DBA.RDF_QUAD where G = "graph" and S = "key";
del_cnt := del_cnt + row_count ();
delete from DB.DBA.RDF_QUAD where G = "graph" and O = "key";
del_cnt := del_cnt + row_count ();
delete from DB.DBA.RDF_QUAD where G = "graph" and S = "cert";
del_cnt := del_cnt + row_count ();
delete from DB.DBA.RDF_QUAD where G = "graph" and O = "cert";
del_cnt := del_cnt + row_count ();
}
}
-- dbg_obj_print (del_cnt);
if (del_cnt > 0)
http_value ('The claim is deleted', 'div');
cert_subject := get_certificate_info (2, null, 0);
cert_val_not_before := get_certificate_info (4, null, 0);
cert_val_not_after := get_certificate_info (5, null, 0);
cert_fingerprint := get_certificate_info (6, null, 0, null, 'sha1');
cert_fingerprint := replace (cert_fingerprint, ':', '');
?>
You can revoke a mirrored WebID claim belong to you using delete functionality.
SAN:
Subject:
Issued:
Expiry:
Fingerprint (SHA1):
Subject
Issued
Expiry
?key ;
?subject ;
?fingerprint ;
?before ;
?after .
} } order by asc (?after) ) x do
{
declare not_before, not_after, star varchar;
not_before := cast ("before" as date);
not_after := cast ("after" as date);
if ("fingerprint" = cert_fingerprint)
star := '* ';
else
star := '';
?>
Delete
No mirrored claims found
¶ certgen_html/details.vspß
Certificate details
Name (mandatory):
Organization:
E-mail:
WebId: />
onclick="javascript:toggle_uri(this);"/> Use proxy IRI in SAN
WebID Identity
WebID & S/MIME (email) Identity
S/MIME (email) Identity
Code Signing Identity
HTTP/TLS Server Identity
Certification Authority (CA) Identity
Key Strength:
512
1024
2048
Chipher:
SHA
SHA1
SHA256
SHA512
MD5
MD4
MD2
id="btn" onclick="javascript:go_back ('caselect.vsp'); return false;"/>
¶ certgen_html/favicon.icoß '– è f ( N ¨ v h
¨ † h .# ( @ € € €€ € € € €€ €€€ ÀÀÀ ÿ ÿ ÿÿ ÿ ÿ ÿ ÿÿ ÿÿÿ 3333333333333 3333333333333303333337wwws3333333333wwwwww333333333wˆˆˆˆˆˆw3333333wˆˆˆˆˆˆˆˆs33333wˆˆˆˆˆ‡ˆ‡ws333wˆˆˆÿÿÿø‡7wxws7ˆˆˆˆˆÿÿÿø‡33xˆs8ˆˆˆˆˆÿÿø÷33ÿƒ8øˆˆˆˆˆˆˆÿ‹63ˆÿƒ7ÿÿøˆˆˆˆÿÿfDFhÿƒ3ˆÿˆˆÿÿÿÿøDDDGƒ;ˆˆˆÿÿÿÿøDwGwDhƒ;ÿ‡ÿ€÷dÿOˆ„H‡»ÿ€øpð‡dˆOD‡Hƒ»ÿ€÷ððøDˆODxDs»ÿpˆw€ødˆODxHƒ»ø‡‡øxvˆow÷Hƒ»€ÿÿÿÿøfˆxˆtGƒ»ˆÿˆÿÿÿÿø‡fffGxƒ»ÿÿÿÿÿÿøˆˆfffwxƒ»ÿÿÿøˆˆˆˆwx‡gˆ‡ƒ»ÿÿÿˆˆˆxˆ‡ˆˆˆøƒ»ˆˆˆˆˆˆˆˆˆÿˆÿøs»»»³xÿÿÿøÿÿˆÿø3»»»³8ÿÿÿøø‡ˆƒ3»»»»»ˆˆxˆ‡ˆˆs333»»»»³;333333333»»»»³;»33333330 »»»»»»³33333330 »»»»»³³333330 à À € € € À à ( € € €€ € € € €€ €€€ ÀÀÀ ÿ ÿ ÿÿ ÿ ÿ ÿ ÿÿ ÿÿÿ www ˆˆˆv ˆÿˆˆ‡ gˆˆˆ‡ xˆ‡wxˆˆp‡xÿ÷wx€wÿÿ†ÌGpÿøÿvfÇp‡wˆvfÇpÿÿø†fhpÿˆ‡ˆwˆ€÷wxwwwp÷ÿx€ˆ ÷ÿ÷ÿ €ÿoö‡ € € üǶðüÀð À à ààçŸà( @ Ë„ ŽŠ‚ ÖÄŠ »ÅÉ !!‰ ÒâÊ ¶†F ’O5 fŠ¾ NNJ è¥ ¨Ãã ~~v ´k! Ýãç ÄÔé ŠŠ> •¥» "F’ ¦¦– €¨Ö ج&