Example of using system ssl to sign some data

System SSL, also known as GS kit, provides an API for doing

  • TLS handshakes
  • Keyring manipulation
  • Encryption and signing of data

This blog post covers how to sign data. I wrote it because I could not find useful samples to get me started.

Signing data

To digitally sign data, you

  • perform a check sum calculation on the data,
  • encrypt the checksum with a private key,
  • package up make the data, the encrypted checkum, and the originator’s public certificate.

The recipient

  • checks the validity of the certificate
  • extracts the public key
  • decrypts the encrypted checksum
  • does a checksum of the enclosed data
  • compares the two checksums.

The checksums should match.

How the defining structures work together

Reference to fields

The definition of a record read from a keyring is

typedef struct _gskdb_record {
gskdb_record_type recordType;
gsk_octet recordFlags;
gsk_octet rsvd_1[1];
gsk_int32 recordId;
gsk_int32 issuerRecordId;
char * recordLabel;
union {
x509_certificate certificate;
pkcs_cert_request request;
} u;
pkcs_private_key_info privateKey;
gsk_octet rsvd_2[16];
} gskdb_record;

This has information about certificate, and the private key.

If you have a variable pRecord as a pointer to this structure, you can refer to the private key as pRecord->privateKey.

Because this structure can be used for both a certificate and a certificate request to refer to a certificate you have to use pRecord->u.certificate to locate the certificate.

Arrays of objects

Some API functions take one certificate, and others take an array of certificates. See Arrays of objects.

To sign some data

printf("....SIGN the data\n");
// pRecord points to the default record
gsk_buffer indata;
gsk_buffer outdata;
// Create the data to sign
indata.data = "ABCDEF";
indata.length = 6;
outdata.data ="OUTDATA "; // dummy data
outdata.length = 6 ;
// Define the certificate(s) to be used
pkcs_certificate cert;
cert.type = pkcs_certtype_certificate ;
cert.u. certificate = pRecord -> u.certificate;
pkcs_cert_key cert_key[1];
cert_key[0].certificate = cert;
cert_key[0].privateKey = pRecord -> privateKey;
// create our structure of an array of keys
// Note the structure is pkcs_cert_key>s< which contains
// one or more cert_key structures.
pkcs_cert_keys cert_keys;
cert_keys.count = 1;
cert_keys.certKeys = &cert_key[0];
// pkcs_certificates certs;
gsk_process_option po;
po.enforce_keyusage = 0;
po.enforce_content_length = 0;
po.enforce_keyparity = 0;
po.create_detached_signature = 0;
gskrc = gsk_make_signed_data_msg_extended
(po, // no options
0, // version
x509_alg_sha1Digest, // algoritm
1, // include certs in the output
&cert_keys, // the certs to use
0, // no ca certs
&indata,
0, // no attrib signers
&outdata);
if (gskrc == 0)
printf("gsk_make_signed_data_msg_extended worked\n");
else
{
printf("gsk_make_signed_data_msg_extended. %8.8x %s\n",
gskrc,gsk_strerror(gskrc));
return 8;
}
printf("Outdata length %i\n",outdata.length);
printHex(stdout,outdata.data,outdata.length);

This produced

00000000 : 3082048C 06092A86 4886F70D 010702A0  ................ .b.....f.f7..... 
00000010 : 82047D30 82047902 0100310B 30090605 ................ b.'.b.`.........
00000020 : 2B0E0302 1A050030 1506092A 864886F7 ................ ............f.f7
00000030 : 0D010701 A0080406 C1C2C3C4 C5C6A082 ................ ........ABCDEF.b
00000040 : 03023082 02FE3082 01E6A003 02010202 ................ ...b...b.W......
00000050 : 0168300D 06092A86 4886F70D 01010B05 ................ .......f.f7.....
00000060 : 00303031 0E300C06 0355040A 1305434F ................ ...............|
00000070 : 4C494E31 0B300906 0355040B 13024341 ................ <.+.............
...
00000460 : B6CBA3F3 48B5C9CD 76063F2D 007840A7 ................ ..t3..I....... x
00000470 : 0C8EF6FE 5442459E 47F6C1D0 12F1247E ................ ..6......6A}.1.=
00000480 : 0DC79B03 7723D129 078D1DB9 812F6EB9 ................ .G....J.....a.>.

In the data is

  • ABCDE – the original data
  • 3082048c – I recognise this as ANS-1 encoding. (ASN.1) is a standard interface description language (IDL) for defining data structures that can be serialized and deserialized in a cross-platform way. It is broadly used in telecommunications and computer networking, and especially in cryptography.
    • For example 048c is the length of data following

Once the signature has been obtained, it can be externalised (such as writing to a file) and sent to a remote site.

Because the data is in hexadecimal you may wish to convert it to EBCDIC for transport. You can use the

gsk_encode_base64 (gsk_buffer input_data,gsk_buffer_output_data);

to encode the data and use the gsk_decode_base64() to decode it.

Validate the data

The recipient can check that the signature and certificates are valid.

// Process the validation of the signature
// The list of input signatures
pkcs_certificates certs;
certs.count = 1;
certs.certificates = &cert;
gsk_attributes_signers as;
gsk_buffer temp; // process the data into temp.
printf("============READSIGNED======\n");
gsk_boolean ul; // were local certificates used?
gskrc = gsk_read_signed_data_msg_extended(
po, // no option
NULL, // no local certificates provided / local_certificates,
&outdata, // the signed data
&ul, // Set if certs were set locally or not
NULL, // returned cert not needed // msg_certificates
NULL, // signer_certificates
&as, // attrbute signers
&temp);
if (gskrc == 0)
{
printf("gsk_read_signed_data_msg_extended worked\n");
printf("Use local certificates %i\n",ul);
printHex(stdout,temp.data,temp.length);
}
else
{
printf("gsk_read_signed_data_msg_extended. %8.8x %s\n",
gskrc,gsk_strerror(gskrc));
return 8;
}

When this executed it produced

gsk_read_signed_data_msg_extended worked
Use local certificates 0
00000000 : C1C2C3C4 C5C6 ...... ABCDEF

which matches the original input data.

With

gskrc = gsk_read_signed_data_msg_extended(
po, // no option
NULL, // no local certificates provided / local_certificates,
...

Only certificates in the data were used. “Use local certificates” was 0.

When

gskrc = gsk_read_signed_data_msg_extended(
po, // no option
&certs, // use local certificates provided
...

it used the certificate(s) from my keyring. “Use local certificates” was 1.

My final code was

pkcs_certificates msgcerts;
pkcs_certificates signercerts;
gsk_attributes_signers as;
gskrc = gsk_read_signed_data_msg_extended(
po, // no option
&certs, // local_certificates,
&outdata, // stread output
&ul, // Set if certs were set locally or not
&msgcerts, // returned msg_certificates
&signercerts, // signer_certificates
&as, // attrbute signers
&temp);
if (gskrc == 0)
{
printf("gsk_read_signed_data_msg_extended worked\n");
printf("Use local certificates %i\n",ul);
printHex(stdout,temp.data,temp.length);
printf("====MSGCERTS+++\n");
// print_pkcs_certificates(&msgcerts);
print_certs(&msgcerts);
printf("====Signers++\n");
print_certs(&signercerts);
// print_pkcs_certificates(&signercerts);
}
else
{
printf("gsk_read_signed_data_msg_extended. %8.8x %s\n",
gskrc,gsk_strerror(gskrc));
return 8;
}