x400_mssend_msg_tok_sign.c
1 /* Copyright (c) 2009-2014, Isode Limited, London, England.
2  * All rights reserved.
3  *
4  * Acquisition and use of this software and related materials for any
5  * purpose requires a written licence agreement from Isode Limited,
6  * or a written licence from an organisation licenced by Isode Limited
7  * to grant such a licence.
8  *
9  */
10 
11 /*
12  *
13  * @VERSION@
14  *
15  *
16  * Simple example program for submitting a message via a message store.
17  * The security environment is set up so that messages are signed with
18  * a per recipient message token.
19  */
20 
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <string.h>
24 
25 #ifndef _WIN32
26 #include <unistd.h>
27 #endif
28 #include <fcntl.h>
29 #include <errno.h>
30 
31 #include <x400_msapi.h>
32 #include <seclabel_api.h> /* For security labels */
33 #include "example.h"
34 #include "ms_example.h"
35 #include "time.h"
36 
37 /* uncomment this if you want a second recipient.
38  * NB as the recipient name is the same, M-Switch
39  * removes the duplicate envelope recips */
40 /*
41 #define tworecips 1
42 */
43 
44 /* uncomment this to cause the API to generate msg_seq_nums which
45  * increment by 1 per message per session */
46 #define FIRST_SEQ_NUM 2
47 
48 #ifdef FIRST_SEQ_NUM
49 int seq_num_val_1 = FIRST_SEQ_NUM;
50 int seq_num_val_2 = FIRST_SEQ_NUM + 100;
51 #endif
52 
53 /* set this to non zero to cause the IA5 body part to be an attachment */
54 int send_ia5_as_att = 0;
55 
56 /*
57 #define ADD_MOAC
58 */
59 
60 static char *optstr = "u37m:d:p:w:M:D:P:W:r:o:O:r:g:G:c:l:R:y:C:iaqsAve:x:b:f:Y:S:j:";
61 
62 /* These are the data items used to construct the message for submission */
63 static char *default_recip = "/CN=P7User1/OU=sales/O=attlee/PRMD=TestPRMD/ADMD=TestADMD/C=GB/";
64 char *recip;
65 char *recip2;
66 static char *content_id = "030924.140212";
67 static const char text[] = "First line\r\nSecond line\r\n";
68 
69 int adding_sec_label = 1;
70 
71 /* local functions */
72 
73 static void usage(void) ;
74 static int send_msg(
75  int contype,
76  char *orn,
77  char *def_dn,
78  char *pa,
79  char *password);
80 
81 static int submit_msg(
82  char *orn,
83  struct X400msSession *sp /* session object */
84 );
85 
86 static int setup_default_new_sec_env(
87  struct X400msSession *sp,
88  char *identity_filename,
89  char *pw
90 );
91 
92 
93 static int setup_default_old_sec_env(
94  struct X400msSession *sp,
95  char *id,
96  char *dn,
97  char *pw
98 );
99 
100 #ifdef notused
101 static int setup_msg_new_sec_env(
102  struct X400msMessage *mp, /* message object */
103  char *identity_filename,
104  char *pw
105 );
106 
107 
108 static int setup_msg_old_sec_env(
109  struct X400msMessage *mp, /* message object */
110  char *id,
111  char *dn,
112  char *pw
113 );
114 
115 static int setup_recip_new_sec_env(
116  struct X400Recipient *rp, /* recipient object */
117  char *identity_filename,
118  char *pw /* passphrase for private key in pkcs12 file */
119 );
120 
121 static int setup_recip_old_sec_env(
122  struct X400Recipient *rp, /* recipient object */
123  char *id, /* x509 identity (directory with x509 subdir) */
124  char *dn, /* DN to use as subject of the X.509 identity */
125  char *pw /* passphrase for private key in pkcs12 file */
126 );
127 
128 #endif
129 
130 
131 static int add_sec_label(
132  struct X400msMessage *mp /* message object */
133 );
134 
135 static int add_recip(
136  struct X400msMessage *mp, /* message object */
137  char *recip
138 );
139 
140 static int add_content(
141  struct X400msMessage *mp /* message object */
142 );
143 
144 static int add_binary_bp(
145  struct X400msMessage *mp
146 );
147 
148 static int add_ftbp(
149  struct X400msMessage *mp
150 );
151 
152 static int add_ia5_str(
153  struct X400msMessage *mp
154 );
155 
156 /* start here */
157 int main (
158  int argc,
159  char **argv
160 )
161 {
162  char pa[BUFSIZ];
163  char orn[BUFSIZ];
164  char *def_oraddr;
165  char *def_dn;
166  char *def_pa;
167  int contype;
168  int status;
169  char password[BUFSIZ];
170 
171  if (get_args(argc, argv, optstr)) {
172  usage();
173  exit(-1);
174  }
175 
176  printf("Connection type (0 = P7, 1 = P3 submit only, 2 = P3 both directions) [%d]: ", x400_contype);
177  contype = ic_fgetc(x400_contype, stdin);
178  if (contype != 10)
179  ic_fgetc(x400_contype, stdin);
180 
181  if ( contype < '0' || '2' < contype )
182  contype = x400_contype;
183  else
184  contype -= '0';
185 
186  if (contype == 0) {
187  def_oraddr = x400_ms_user_addr;
188  def_dn = x400_ms_user_dn;
189  def_pa = x400_ms_presentation_address;
190  } else {
191  def_oraddr = x400_mta_user_addr;
192  def_dn = x400_mta_user_dn;
193  def_pa = x400_mta_presentation_address;
194  }
195 
196  printf("Your ORAddress [%s] > ", def_oraddr);
197  ic_fgets (orn, sizeof orn, stdin);
198 
199  if ( orn[strlen(orn)-1] == '\n' )
200  orn[strlen(orn)-1] = '\0';
201 
202  if (orn[0] == '\0')
203  strcpy(orn, def_oraddr);
204 
205  /* Prompt for password; note: reflected. */
206  printf ("Password [%s]: ",
207  contype == 0 ? x400_p7_password : x400_p3_password);
208  if ( ic_fgets (password, sizeof password, stdin) == NULL )
209  exit (1);
210 
211  if (password[strlen(password)-1] == '\n' )
212  password[strlen(password)-1] = '\0';
213  if (password[0] == '\0')
214  strcpy(password, contype == 0 ? x400_p7_password : x400_p3_password);
215 
216  /* Presentation Address */
217  printf("Presentation Address [%s] > ", def_pa);
218  ic_fgets (pa, sizeof pa, stdin);
219 
220  if ( pa[strlen(pa)-1] == '\n' )
221  pa[strlen(pa)-1] = '\0';
222 
223  if (pa[0] == '\0')
224  strcpy(pa, def_pa);
225 
226  printf("sending message using session 1\n");
227  if ((status = send_msg(contype, orn, def_dn, pa, password))
228  != X400_E_NOERROR ) {
229  fprintf (stderr, "Error in sending message\n");
230  exit (status);
231  }
232 
233 #ifdef notdef
234  printf("sending message using session 2\n");
235  if ((status = send_msg(contype, orn, def_dn, pa, password))
236  != X400_E_NOERROR ) {
237  fprintf (stderr, "Error sending message\n");
238  exit (status);
239  }
240 #endif
241 
242  return (status);
243 }
244 
245 static int send_msg(
246  int contype,
247  char *orn,
248  char *def_dn,
249  char *pa,
250  char *password
251 )
252 {
253  struct X400msSession *sp; /* session object */
254 
255  int status;
256  int nummsg;
257 
258 
259  /* Open an API session */
260  status = X400msOpen (contype, orn, def_dn, password, pa, &nummsg, &sp);
261  if ( status != X400_E_NOERROR ) {
262  fprintf (stderr, "Error in Open: %s\n", X400msError (status));
263  fprintf (stderr, "%s %s %s\n", orn, def_dn, pa);
264  return (status);
265  }
266 
267  /* setup logging */
268  X400msSetStrDefault(sp, X400_S_LOG_CONFIGURATION_FILE, "x400api.xml", 0);
269 
270  /* Set up the security environment.
271  *
272  * In R15.0 this need only be the name of a trusted certificate directory.
273  *
274  * Prior to R15.0, the ID is specified as a pathname, in which the
275  * subdirectory "x509" is expected to contain one or more PKCS12
276  * files. The appropriate Digital Identity is determined from the
277  * DN of the subject, and the passphrase is used to decrypt the
278  * private key. NB even though we're not going to use our cert,
279  * (as we're going to use the cert in the message to check the MOAC
280  * we need to do this due to a limitation in the underlying X.509
281  * layer.
282  */
283 
284  if (use_new_sec_env) {
285  status = setup_default_new_sec_env(sp, identity_filename, passphrase);
286  } else {
287  status = setup_default_old_sec_env(sp, security_id,
288  identity_dn, passphrase);
289  }
290 
291  if ( status != X400_E_NOERROR ) {
292  fprintf (stderr, "Can't setup security environment\n");
293  return (status);
294  }
295 
296  printf("sending message 1\n");
297  status = submit_msg(orn, sp);
298  if ( status != X400_E_NOERROR ) {
299  fprintf (stderr, "Can't submit\n");
300  return (status);
301  }
302 
303 /*
304  printf("sending message 2\n");
305  status = submit_msg(orn, sp);
306  if ( status != X400_E_NOERROR ) {
307  fprintf (stderr, "Can't submit\n");
308  return (status);
309  }
310  printf("sending message 3\n");
311  status = submit_msg(orn, sp);
312  if ( status != X400_E_NOERROR ) {
313  fprintf (stderr, "Can't submit\n");
314  return (status);
315  }
316 */
317  status = X400msClose (sp);
318  if ( status != X400_E_NOERROR ) {
319  fprintf (stderr, "X400msClose returned error: %s\n", X400msError (status));
320  return (status);
321  }
322  return status;
323 }
324 
325 static int submit_msg(
326  char *orn,
327  struct X400msSession *sp /* session object */
328 )
329 {
330  struct X400msMessage *mp; /* message object */
331 #ifdef tworecips
332  struct X400Recipient *rp2; /* recipient object */
333 #endif
334  char tmp[BUFSIZ];
335  static int msg_num = 0;
336  int status;
337 
338  msg_num++;
339 
340  if (x400_default_recipient != NULL) {
341  recip = x400_default_recipient;
342  recip2 = x400_default_recipient;
343  } else {
344  recip = default_recip;
345  recip2 = default_recip;
346  }
347 
348  printf("Message recipient [%s]: ", recip);
349  ic_fgets (tmp, sizeof tmp, stdin);
350 
351  if ( tmp[strlen(tmp)-1] == '\n' )
352  tmp[strlen(tmp)-1] = '\0';
353  if (strlen(tmp) != 0) {
354  recip = strdup(tmp);
355  recip2 = strdup(tmp);
356  }
357 
358  printf("Subject [%s]: ", subject);
359  ic_fgets (tmp, sizeof tmp, stdin);
360 
361  if ( tmp[strlen(tmp)-1] == '\n' )
362  tmp[strlen(tmp)-1] = '\0';
363  if (strlen(tmp) != 0)
364  subject = strdup(tmp);
365 
366  printf("\n");
367  status = X400msMsgNew (sp, X400_MSG_MESSAGE, &mp);
368  if ( status != X400_E_NOERROR ) {
369  fprintf (stderr, "x400msMsgNew returned error: %s\n",
370  X400msError (status));
371  return (status);
372  }
373 
374 #ifdef use_diff_sec_env_second_msg
375  if (msg_num > 1) {
376  /* set up a security env for the message - this will be used in
377  * preference to the default security env */
378  status = setup_msg_sec_env(mp, "/root",
379  "cn=P7User1,o=Address Book,c=GB", "secret");
380  if ( status != X400_E_NOERROR ) {
381  fprintf (stderr, "setup_msg_sec_env returned error: %s\n",
382  X400msError (status));
383  /* ignore - let's see if the defaults work */
384  }
385  }
386 #endif
387 
388 #define S4404_ENCRYPT
389 #ifdef S4404_ENCRYPT
390  /* Instruct the X400msMsgSend() function to generate a
391  * an S4406 (PCT) encrypted message.
392  * The default attributes will be used unless the attributes are
393  * also included in the message eg by calling setup_msg_sec_env() above */
394  status = X400msMsgAddIntParam (mp, X400_N_S4406, 1);
395  if ( status != X400_E_NOERROR ) {
396  fprintf (stderr, "x400msMsgAddStrParam returned error: %s\n",
397  X400msError (status));
398  return (status);
399  } else {
400  fprintf (stderr, "encrypting message as S4406 (PCT) \n");
401  }
402 #endif
403 #ifdef ADD_MOAC
404  /* Instruct the X400msMsgSend() function to generate a
405  * MOAC (signature) for
406  * the message Instruct the X400msMsgSend() function to generate a MOAC
407  * (signature) for the message
408  * The default attributes will be used unless the attributes are
409  * also included in the message eg by calling setup_msg_sec_env() above */
410  status = X400msMsgAddIntParam (mp, X400_B_SEC_GEN_MOAC, 1);
411  if ( status != X400_E_NOERROR ) {
412  fprintf (stderr, "x400msMsgAddStrParam returned error: %s\n",
413  X400msError (status));
414  return (status);
415  } else {
416  fprintf (stderr, "Adding MOAC\n");
417  }
418 #endif
419 
420 
421  /* originator */
422  status = X400msMsgAddStrParam (mp, X400_S_OR_ADDRESS, orn, -1);
423  if ( status != X400_E_NOERROR ) {
424  fprintf (stderr, "x400msMsgAddStrParam returned error: %s\n",
425  X400msError (status));
426  return (status);
427  }
428 
430  "CN=originator;c=gb", -1);
431  if ( status != X400_E_NOERROR ) {
432  fprintf (stderr, "x400msMsgAddStrParam returned error: %s\n",
433  X400msError (status));
434  return (status);
435  }
436 
437  if (adding_sec_label) {
438  status = add_sec_label (mp);
439  if ( status != X400_E_NOERROR ) {
440  fprintf (stderr, "Failed to add Security Label: %s\n",
441  X400msError (status));
442  return (status);
443  } else {
444  fprintf (stderr, "added Security Label\n");
445  }
446  }
448  content_id, -1);
449  if ( status != X400_E_NOERROR ) {
450  fprintf (stderr, "x400msMsgAddStrParam returned error: %s\n",
451  X400msError (status));
452  return (status);
453  }
454 
455  /*
456  status = X400msMsgAddStrParam (mp, X400_S_SUBJECT, subject, -1);
457  if ( status != X400_E_NOERROR ) {
458  fprintf (stderr, "x400msMsgAddStrParam returned error: %s\n",
459  X400msError (status));
460  return (status);
461  }
462 */
463 
464  /* Priority: X.400 0 - normal, 1 - non-urgent, 2 - urgent */
465  /* Military 0 - deferred, 1 - routine, 2 - priority \n"); */
466  /* 3 - immediate, 4 - flash, 5 - override \n"); */
467  printf("military message priority is %d (%s) \n",
468  x400_default_priority,
469  get_x400_pty_str_from_4406(x400_default_priority));
470  status = X400msMsgAddIntParam (mp, X400_N_PRIORITY,
471  get_x400_pty_from_4406(x400_default_priority));
472  if ( status != X400_E_NOERROR ) return (status);
473 
474  /* Priority qaulifier: 0 - low, 1 - high */
475  printf("military message priority qualifer is %d ( 0 - low, 1 - high)\n",
476  get_x400_pty_qual_from_4406(x400_default_priority));
478  get_x400_pty_qual_from_4406(x400_default_priority));
479  if ( status != X400_E_NOERROR ) return (status);
480 
481  /* subject */
482  {
483  time_t t;
484  time(&t);
485  char tmp_buffer[255];
486  // NB strip newline from ctime result
487  snprintf(tmp_buffer, 244, "%s '%s' '%.19s'",
488  subject, get_x400_pty_str_from_4406(x400_default_priority), ctime(&t));
489  printf("Subject is '%s'\n", tmp_buffer);
490  status = X400msMsgAddStrParam (mp, X400_S_SUBJECT, tmp_buffer, -1);
491  if ( status != X400_E_NOERROR ) {
492  fprintf (stderr, "x400msMsgAddStrParam returned error: %s\n",
493  X400msError (status));
494  exit (status);
495  }
496  }
497 
498  /* content type */
499  //status = X400msMsgAddStrParam (mp, X400_S_EXTERNAL_CONTENT_TYPE, "1.3.26.0.4406.0.4.1", -1);
500  status = X400msMsgAddStrParam (mp, X400_S_EXTERNAL_CONTENT_TYPE, "1.2.840.113549.1.9.16.1.6", -1);
501  if ( status != X400_E_NOERROR ) {
502  fprintf (stderr, "x400msMsgAddStrParam returned error: %s\n", X400msError (status));
503  exit (status);
504  }
505 
506  if (add_recip(mp, recip) != X400_E_NOERROR) {
507  fprintf (stderr, "add_recip() returned error: %s\n",
508  X400msError (status));
509  return (status);
510  }
511 
512  /*
513  * Use this to add a second recip
514  *
515  if (add_recip(mp, "/G=P7/S=User2/ou=acp127/O=centos64-1/ADMD= /C=GB/") != X400_E_NOERROR) {
516  fprintf (stderr, "add_recip() returned error: %s\n",
517  X400msError (status));
518  return (status);
519  }
520  */
521 
522  if (add_content(mp) != X400_E_NOERROR) {
523  fprintf (stderr, "add_content() returned error: %s\n",
524  X400msError (status));
525  return (status);
526  }
527 
528  status = X400msMsgSend (mp);
529  if ( status != X400_E_NOERROR ) {
530  fprintf (stderr, "x400msMsgSend returned error: %s\n",
531  X400msError (status));
532  return (status);
533  } else {
534  printf("Message submitted successfully\n");
535  }
536 
537  status = X400msMsgDelete (mp, 0);
538  if ( status != X400_E_NOERROR ) {
539  fprintf (stderr, "x400msMsgDelete returned error: %s\n",
540  X400msError (status));
541  return (status);
542  }
543 
544  mp = NULL;
545  return (status);
546 }
547 
548 
549 static int add_recip(
550  struct X400msMessage *mp, /* message object */
551  char *local_recip
552 )
553 {
554  int status;
555  struct X400Recipient *rp; /* recipient object */
556 
557  /* first recip */
558  status = X400msRecipNew (mp, X400_RECIP_STANDARD, &rp);
559  if ( status != X400_E_NOERROR ) {
560  fprintf (stderr, "x400msRecipNew returned error: %s\n",
561  X400msError (status));
562  return (status);
563  }
564 
565  /* put precedence extension into primary recipient */
566  status = X400msRecipAddIntParam (rp, X400_N_PRECEDENCE, 2);
567  if ( status != X400_E_NOERROR ) {
568  fprintf (stderr, "x400msRecipAddIntParam returned error: %s\n",
569  X400msError (status));
570  return (status);
571  }
572 
573 
574  status = X400msRecipAddStrParam (rp, X400_S_OR_ADDRESS, local_recip, -1);
575  if ( status != X400_E_NOERROR ) {
576  fprintf (stderr, "x400msRecipAddStrParam returned error: %s\n",
577  X400msError (status));
578  return (status);
579  }
580 
582  "CN=recipient;c=gb", -1);
583  if ( status != X400_E_NOERROR ) {
584  fprintf (stderr, "x400msRecipAddStrParam returned error: %s\n",
585  X400msError (status));
586  return (status);
587  }
588 
589  /* cause a PODR to be added as a recip extension */
591  if ( status != X400_E_NOERROR ) {
592  fprintf (stderr, "x400msMsgAddStrParam returned error: %s\n",
593  X400msError (status));
594  return (status);
595  }
596 
597  /* cause a Content Integrity Check to be added as a recip extension */
599  if ( status != X400_E_NOERROR ) {
600  fprintf (stderr, "X400msRecipAddIntParam returned error: %s\n",
601  X400msError (status));
602  return (status);
603  }
604 
605  /* Ask for Message Token for this recip */
606  fprintf (stderr, "requesting token\n");
608  if ( status != X400_E_NOERROR ) {
609  fprintf (stderr, "x400msRecipAddStrParam returned error: %s\n",
610  X400msError (status));
611  return (status);
612  }
613 
614 #ifdef FIRST_SEQ_NUM
615  /* Add sequence num */
617  seq_num_val_1);
618  if ( status != X400_E_NOERROR ) {
619  fprintf (stderr, "x400msRecipAddStrParam returned error: %s\n",
620  X400msError (status));
621  return (status);
622  } else {
623  fprintf (stderr, "Added sequence number %d for token\n", seq_num_val_1);
624  }
625  seq_num_val_1++;
626 #endif
627 
628 
629  /* Ask for +ve and -ve delivery reports */
630  /* status = X400msRecipAddIntParam (rp, X400_N_REPORT_REQUEST, 2); */
631  /* Ask for no +ve and -ve delivery reports */
633  if ( status != X400_E_NOERROR ) {
634  fprintf (stderr, "x400msRecipAddStrParam returned error: %s\n",
635  X400msError (status));
636  return (status);
637  }
638 
639  /* Ask for +ve and -ve read receipts */
641  if ( status != X400_E_NOERROR ) {
642  fprintf (stderr, "x400msRecipAddStrParam returned error: %s\n",
643  X400msError (status));
644  return (status);
645  }
646  return X400_E_NOERROR;
647 }
648 
649 
650 static int setup_default_new_sec_env(
651  struct X400msSession *sp,
652  char *idf,
653  char *pw
654 )
655 {
656  int status;
657 
658  fprintf (stderr, "using new_sec_nv %s\n", idf);
659  /* Filename of the Digital Identity (PKCS12 file)
660  * This supersedes the obsolescent X400_S_SEC_IDENTITY,
661  * X400_S_SEC_IDENTITY_DN attributes */
663  idf, -1);
664  if ( status != X400_E_NOERROR ) {
665  fprintf (stderr, "X400msSetStrDefault returned error: %s\n",
666  X400msError (status));
667  return (status);
668  }
669 
670  /* passphrase used to open the Identity */
672  if ( status != X400_E_NOERROR ) {
673  fprintf (stderr, "X400msSetStrDefault returned error: %s\n",
674  X400msError (status));
675  return (status);
676  }
677 
678  /* test the sec env */
679  status = X400msTestSecurityEnv (sp);
680  if ( status != X400_E_NOERROR ) {
681  fprintf (stderr, "X400msTestSecurityEnv returned error: %s\n",
682  X400msError (status));
683  return (status);
684  }
685 
686  return status;
687 }
688 
689 
690 static int setup_default_old_sec_env(
691  struct X400msSession *sp,
692  char *id,
693  char *dn,
694  char *pw
695 )
696 {
697  int status;
698 
699  fprintf (stderr, "using old_sec_nv\n");
700  /* first set a default security identity. This passes in the name of a
701  * directory, which contains an x509 subdirectory in which all Identities
702  * are held */
704 
705  /* select by DN which Identity is to be used (if there are several)
706  * Currently these must be PKCS12 files */
707  status = X400msSetStrDefault (sp, X400_S_SEC_IDENTITY_DN, dn, -1);
708  if ( status != X400_E_NOERROR ) {
709  fprintf (stderr, "X400msSetStrDefault returned error: %s\n",
710  X400msError (status));
711  return (status);
712  }
713 
714  /* passphrase used to open the Identity */
716  if ( status != X400_E_NOERROR ) {
717  fprintf (stderr, "X400msSetStrDefault returned error: %s\n",
718  X400msError (status));
719  return (status);
720  }
721  return status;
722 }
723 
724 #ifdef notused
725 static int setup_msg_new_sec_env(
726  struct X400msMessage *mp, /* message object */
727  char *identity_filename,
728  char *pw /* passphrase for private key in pkcs12 file */
729 )
730 {
731  int status;
732 
733  /* Filename of the Digital Identity (PKCS12 file)
734  * This supersedes the obsolescent X400_S_SEC_IDENTITY,
735  * X400_S_SEC_IDENTITY_DN attributes */
737  identity_filename, -1);
738  if ( status != X400_E_NOERROR ) {
739  fprintf (stderr, "X400msMsgAddStrParam returned error: %s\n",
740  X400msError (status));
741  return (status);
742  }
743 
744  printf("setting up new message security env %s\n", identity_filename);
745 
746  /* security additions */
748  if ( status != X400_E_NOERROR ) {
749  fprintf (stderr, "x400msMsgAddStrParam returned error: %s\n",
750  X400msError (status));
751  return (status);
752  }
753  return (status);
754 }
755 
756 static int setup_msg_old_sec_env(
757  struct X400msMessage *mp, /* message object */
758  char *id, /* x509 identity (directory with x509 subdir) */
759  char *dn, /* DN to use as subject of the X.509 identity */
760  char *pw /* passphrase for private key in pkcs12 file */
761 )
762 {
763  int status;
764 
765  printf("setting up message security env %s\n", id);
766 
767  /* overide the default security environment by specifying a new set of
768  * attibutes, and put them into the message */
769  /* security additions */
770  status = X400msMsgAddStrParam (mp, X400_S_SEC_IDENTITY, id, -1);
771  if ( status != X400_E_NOERROR ) {
772  fprintf (stderr, "x400msMsgAddStrParam returned error: %s\n",
773  X400msError (status));
774  return (status);
775  }
776 
777  /* security additions */
778  status = X400msMsgAddStrParam (mp, X400_S_SEC_IDENTITY_DN, dn, -1);
779  if ( status != X400_E_NOERROR ) {
780  fprintf (stderr, "x400msMsgAddStrParam returned error: %s\n",
781  X400msError (status));
782  return (status);
783  }
784 
785  printf("setting up new message security env %s\n", identity_filename);
786 
787  /* security additions */
789  if ( status != X400_E_NOERROR ) {
790  fprintf (stderr, "x400msMsgAddStrParam returned error: %s\n",
791  X400msError (status));
792  return (status);
793  }
794  return (status);
795 }
796 
797 static int setup_recip_new_sec_env(
798  struct X400Recipient *rp, /* recipient object */
799  char *identity_filename,
800  char *pw /* passphrase for private key in pkcs12 file */
801 )
802 {
803  int status;
804 
805  printf("setting up recipient security env %s\n", identity_filename);
806 
807  /* Filename of the Digital Identity (PKCS12 file)
808  * This supersedes the obsolescent X400_S_SEC_IDENTITY,
809  * X400_S_SEC_IDENTITY_DN attributes */
811  identity_filename, -1);
812  if ( status != X400_E_NOERROR ) {
813  fprintf (stderr, "X400msRecipAddStrParam returned error: %s\n",
814  X400msError (status));
815  return (status);
816  }
817 
818  status = X400msRecipAddStrParam (rp,
820  if ( status != X400_E_NOERROR ) {
821  fprintf (stderr, "x400msRecipAddStrParam returned error: %s\n",
822  X400msError (status));
823  return (status);
824  }
825 
826  return (status);
827 }
828 
829 
830 static int setup_recip_old_sec_env(
831  struct X400Recipient *rp, /* recipient object */
832  char *id, /* x509 identity (directory with x509 subdir) */
833  char *dn, /* DN to use as subject of the X.509 identity */
834  char *pw /* passphrase for private key in pkcs12 file */
835 )
836 {
837  int status;
838 
839  printf("setting up recipient security env %s\n", id);
840 
841  /* overide the default and message security environment
842  * by specifying a new set of attibutes, and put them
843  * into the recipient security attributes */
844  status = X400msRecipAddStrParam (rp, X400_S_SEC_IDENTITY, id, -1);
845  if ( status != X400_E_NOERROR ) {
846  fprintf (stderr, "x400msRecipAddStrParam returned error: %s\n",
847  X400msError (status));
848  return (status);
849  }
850 
851  status = X400msRecipAddStrParam (rp, X400_S_SEC_IDENTITY_DN, dn, -1);
852  if ( status != X400_E_NOERROR ) {
853  fprintf (stderr, "x400msRecipAddStrParam returned error: %s\n",
854  X400msError (status));
855  return (status);
856  }
857 
858  status = X400msRecipAddStrParam (rp,
860  if ( status != X400_E_NOERROR ) {
861  fprintf (stderr, "x400msRecipAddStrParam returned error: %s\n",
862  X400msError (status));
863  return (status);
864  }
865 
866  return (status);
867 }
868 #endif
869 
870 static int add_sec_label(
871  struct X400msMessage *mp /* message object */
872 )
873 {
874 #define XML_BUFSIZE 1024
875 #define STRING_BUFSIZE 1024
876 
877  const char* xml_filename = "seclabel.xml";
878  char xml_content[XML_BUFSIZE];
879  char str_content[STRING_BUFSIZE];
880  int str_len = STRING_BUFSIZE;
881  FILE *fd = NULL;
882  int status;
883 
884  /* Read in the security label XML file */
885  fd = fopen(xml_filename,"r");
886  if(fd == NULL) {
887  fprintf(stderr,"Failed to open %s : %s\n",
888  xml_filename,strerror(errno));
889  return X400_E_INT_ERROR;
890  }
891 
892  fread(&xml_content,XML_BUFSIZE,1,fd);
893 
894  fclose(fd);
895 
896  status = SecLabelInit("Example program");
897  if (status != SECLABEL_E_NOERROR) {
898  fprintf(stderr, "SecLabelInit returned error %d\n", status);
899  return(X400_E_INT_ERROR);
900  }
901 
902  /* Use SecLabelParse to turn the XML into an octect string */
903  status = SecLabelParse(xml_content,
904  str_content,
905  STRING_BUFSIZE,
906  &str_len);
907 
908  if (status != SECLABEL_E_NOERROR) {
909  fprintf(stderr, "SecLabelParse returned error %d\n", status);
910  return(X400_E_INT_ERROR);
911  }
912 
913  /* Add the octect string to the message pointer */
915  str_content,str_len);
916  if ( status != X400_E_NOERROR ) {
917  fprintf (stderr, "x400msMsgAddStrParam returned error: %s\n",
918  X400msError (status));
919  return (status);
920  }
921  return X400_E_NOERROR;
922 }
923 
924 static int add_content(
925  struct X400msMessage *mp /* message object */
926 )
927 {
928  FILE *fp = NULL;
929  int fs = 0;
930  int status;
931  char *binary_data;
932 
933  /* add some attachments/body parts
934  * Strictly a message simply has a sequence of body parts.
935  * However in human terms, it can be useful to treat the Body Parts
936  * as
937  * - text, i.e. an IA5 or general text attachment
938  * - followed by 0 or more attachments (e.g. documents, images etc)
939  *
940  * The API allows for either style.
941  *
942  * Use the AddStrParam() function to add a text attachment
943  * Use the X400msMsgAddAttachment() function to add a Body Part
944  * Use the X400msMsgAddMessageBodyWType() function to add structured
945  * Body Part (e.g. message, FTBP)
946  */
947 
948  status = X400msMsgAddStrParam (mp, X400_T_ISO8859_1, text, -1);
949  if ( status != X400_E_NOERROR ) {
950  fprintf (stderr, "x400ms returned error: %s\n", X400msError (status));
951  return (status);
952  }
953  printf("Sent 8859 attachment as string:\n%s\n", text);
954 
955  if (send_ia5_as_att) {
956  /* now an IA5 body attachment using the attachment func */
957  status = X400msMsgAddAttachment (mp, X400_T_IA5TEXT,
958  text, strlen(text));
959  if ( status != X400_E_NOERROR ) {
960  printf("failed to add X400_T_IA5TEXT attachment\n");
961  return (status);
962  }
963  printf("Sent IA5 as first attachment:\n%s\n", text);
964  } else {
965  /* now an IA5 attachment using the str func */
966  if (num_of_ia5_bytes == 0) {
967  status = X400msMsgAddStrParam (mp, X400_T_IA5TEXT, text, -1);
968  if ( status != X400_E_NOERROR ){
969  printf("failed to add X400_T_IA5TEXT BP\n");
970  return (status);
971  }
972  printf("Sent IA5 as string in message \n%s\n", text);
973  } else {
974  status = add_ia5_str(mp);
975  if ( status != X400_E_NOERROR ) {
976  printf("failed to add IA5 str\n");
977  return (status);
978  }
979  }
980  }
981 
982  /* now an 8859-1 body attachment using the attachment func */
983  status = X400msMsgAddAttachment (mp, X400_T_ISO8859_1, text, strlen(text));
984  if ( status != X400_E_NOERROR ) {
985  printf("failed to add X400_T_ISO8859_1, attachment\n");
986  return (status);
987  }
988  printf("Sent 8859-1 as attachment:\n%s\n", text);
989 
990  /* or a Binary body part using the bodypart func */
991  status = add_binary_bp(mp);
992  if ( status != X400_E_NOERROR ) {
993  printf("failed to add X400_T_BINARY BP\n");
994  return (status);
995  }
996 
997  /* File Transfer Body Part using the bodypart func */
998  status = add_ftbp(mp);
999  if ( status != X400_E_NOERROR ) {
1000  printf("failed to add X400_T_BINARY BP\n");
1001  return (status);
1002  }
1003 
1004  return status;
1005 
1006  if (filename_to_send != NULL) {
1007  binary_data = (char *) malloc(100000);
1008  if ( binary_data == NULL )
1009  return X400_E_NOMEMORY;
1010  fp = fopen(filename_to_send, "r");
1011  if (fp == (FILE *)NULL) {
1012  printf("Cannot open binary file\n");
1013  return (X400_E_SYSERROR);
1014  }
1015  if ((fs = fread (binary_data, sizeof(char), 100000/sizeof(char), fp))
1016  == -1) {
1017  printf("Cannot read from binary file\n");
1018  return (X400_E_SYSERROR);
1019  }
1020  fclose(fp);
1021 
1022  status = X400msMsgAddAttachment (mp, X400_T_BINARY, binary_data, fs);
1023  if ( status != X400_E_NOERROR ) {
1024  printf("failed to add X400_T_BINARY BP\n");
1025  return (status);
1026  }
1027 
1028  status = X400msMsgAddStrParam (mp, X400_T_IA5TEXT, text, -1);
1029  if ( status != X400_E_NOERROR ){
1030  printf("failed to add X400_T_IA5TEXT BP\n");
1031  return (status);
1032  }
1033  printf("Sent IA5 as string in message \n%s\n", text);
1034 
1035  free (binary_data);
1036 
1037  } else {
1038  printf("no binary file set - not sending X400_T_BINARY\n");
1039  }
1040  return status;
1041 }
1042 
1043 
1044 static int add_ia5_str(
1045  struct X400msMessage *mp
1046 )
1047 {
1048  int status;
1049  char *tmp;
1050  int i;
1051  char *sample_ia5 = {"Here is some sample text to put into the IA5 attachment."};
1052 
1053  if ((tmp = malloc(num_of_ia5_bytes + 1)) == NULL) {
1054  printf("failed to malloc %d bytes\n", num_of_ia5_bytes);
1055  return (X400_E_SYSERROR);
1056  }
1057  strcpy(tmp, text);
1058  for (i = strlen(text) ; i < num_of_ia5_bytes ; i++)
1059  tmp[i] = sample_ia5[i%strlen(sample_ia5)];
1060  tmp[i] = '\0';
1061 
1062  status = X400msMsgAddStrParam (mp, X400_T_IA5TEXT, tmp, strlen(tmp));
1063  if ( status != X400_E_NOERROR ) {
1064  printf("failed to add X400_T_IA5TEXT BP\n");
1065  return (status);
1066  }
1067  printf("Sent %d bytes IA5 as string in message \n%s\n", i, tmp);
1068  return X400_E_NOERROR;
1069 }
1070 
1071 
1072 static int add_binary_bp(
1073  struct X400msMessage *mp
1074 )
1075 {
1076  FILE *fp = NULL;
1077  int fs=0;
1078  char *binary_data;
1079  int status;
1080 
1081  /* or a Binary body part using the bodypart func */
1082  if (filename_to_send != NULL) {
1083  fp = fopen(filename_to_send, "rb");
1084  if (fp == (FILE *)NULL) {
1085  printf("Cannot open binary file\n");
1086  return (X400_E_SYSERROR);
1087  }
1088  binary_data = (char *) malloc(bin_bp_size);
1089  if ( binary_data == NULL )
1090  return X400_E_NOMEMORY;
1091  if ((fs = fread (binary_data, sizeof(char),
1092  bin_bp_size/sizeof(char), fp) ) == -1) {
1093  printf("Cannot read from binary file\n");
1094  free (binary_data);
1095  fclose(fp);
1096  return (X400_E_SYSERROR);
1097  }
1098  fclose(fp);
1099  if (fs < bin_bp_size) {
1100  printf("Cannot read %d bytes from binary file (got %d)\n",
1101  bin_bp_size, fs);
1102  free (binary_data);
1103  return (X400_E_SYSERROR);
1104  }
1105 
1106  status = X400msMsgAddAttachment (mp, X400_T_BINARY, binary_data, fs);
1107  free (binary_data);
1108  if ( status != X400_E_NOERROR ) {
1109  printf("failed to add X400_T_BINARY BP\n");
1110  return (status);
1111  }
1112  printf("Sent %d bytes as X400_T_BINARY BP\n", fs);
1113  } else {
1114  printf("no binary file set - not sending X400_T_BINARY\n");
1115  }
1116  return X400_E_NOERROR;
1117 }
1118 
1119 
1120 static int add_ftbp(
1121  struct X400msMessage *mp
1122 )
1123 {
1124  FILE *fp = NULL;
1125  int fs=0;
1126  char *binary_data;
1127  int status;
1128  struct X400Bodypart *bp;
1129 
1130  /* or a Binary body part using the bodypart func */
1131  if (filename_to_send != NULL) {
1132  fp = fopen(filename_to_send, "rb");
1133  if (fp == (FILE *)NULL) {
1134  printf("Cannot open binary file\n");
1135  return (X400_E_SYSERROR);
1136  }
1137  binary_data = (char *) malloc(bin_bp_size);
1138  if ( binary_data == NULL )
1139  return X400_E_NOMEMORY;
1140  if ((fs = fread (binary_data, sizeof(char),
1141  bin_bp_size/sizeof(char), fp) ) == -1) {
1142  printf("Cannot read from binary file\n");
1143  free (binary_data);
1144  fclose(fp);
1145  return (X400_E_SYSERROR);
1146  }
1147  fclose(fp);
1148  if (fs < bin_bp_size) {
1149  printf("Cannot read %d bytes from binary file (got %d)\n",
1150  bin_bp_size, fs);
1151  free (binary_data);
1152  return (X400_E_SYSERROR);
1153  }
1154 
1156  X400BodypartAddStrParam(bp, X400_S_BODY_DATA, binary_data, fs);
1158  "Test FTBP File", -1);
1159  /* NB this value should have the filename, but not the full path */
1160  /* Ad on Windows backslashes must be escaped with a second backslash */
1161  X400BodypartAddStrParam(bp, X400_S_FTBP_FILENAME, filename_to_send, -1);
1163  "20160801060101.0Z", -1);
1165  "20160801060202.0Z", -1);
1167  status = X400msMsgAddBodypart(mp, bp);
1168  free (binary_data);
1169 
1170  if ( status != X400_E_NOERROR ) {
1171  printf("failed to add X400_T_FTBP BP\n");
1172  return (status);
1173  }
1174  printf("Sent %d bytes as X400_T_FTBP BP\n", fs);
1175  } else {
1176  printf("no binary file set - not sending X400_T_FTBP\n");
1177  }
1178  return X400_E_NOERROR;
1179 }
1180 
1181 
1182 static void usage(void) {
1183 printf("usage: %s\n", optstr);
1184  printf("\t where:\n");
1185  printf("\t -u : Don't prompt to override defaults \n");
1186  printf("\t -3 : Use P3 connection \n");
1187  printf("\t -7 : Use P7 connection \n");
1188  printf("\t -m : OR Address in P7 bind arg \n");
1189  printf("\t -d : DN in P7 bind arg \n");
1190  printf("\t -p : Presentation Address of P7 Store \n");
1191  printf("\t -w : P7 password of P7 user \n");
1192  printf("\t -M : OR Address in P3 bind arg \n");
1193  printf("\t -D : DN in P3 bind arg \n");
1194  printf("\t -P : Presentation Address of P3 server\n");
1195  printf("\t -W : P3 password of P3 user \n");
1196  printf("\t -o : Originator \n");
1197  printf("\t -O : Originator Return Address \n");
1198  printf("\t -r : Recipient\n");
1199  printf("\t -l : Logline\n");
1200  printf("\t -R : Report requests\n");
1201  printf("\t\t : 0 - none, 1 - non-delivery, 2 - delivery (implies 1)\n");
1202  printf("\t -y : Military Priority \n");
1203  printf("\t\t 0 - deferred, 1 - routine, 2 - priority \n");
1204  printf("\t\t 3 - immediate, 4 - flash, 5 - override \n");
1205  printf("\t -C : Content Type (2/22/772/OID) \n");
1206  printf("\t -i : Implicit conversion prohibited = TRUE \n");
1207  printf("\t -a : Alternate Recipient Prohibited = TRUE \n");
1208  printf("\t -q : Content Return Request = TRUE \n");
1209  printf("\t -s : Disclosure of Recipient = FALSE \n");
1210  printf("\t -A : Recipient Reassignment Prohibited = FALSE \n");
1211  printf("\t -v : Conversion with Loss Prohibited = FALSE \n");
1212  printf("\t -e : Security Environment (dir with x509 subdir): obsolete, use -Y <p12file>\n");
1213  printf("\t -x : DN of X.509 Digital Identity\n");
1214  printf("\t -b : Passphrase for private key in PKCS12 file\n");
1215  printf("\t -f : Filename to transfer as binary bp\n");
1216  printf("\t -Y : Filename of PKCS12 file containing Digital Identity\n");
1217  printf("\t -S : Number of bytes to put into Binary BP and FTBP (default 100)\n");
1218  printf("\t -j : Number of bytes to put into IA5 BP (default 100)\n");
1219  return;
1220 }
1221 
1222 
#define X400_S_LOG_CONFIGURATION_FILE
Definition: x400_att.h:1092
int X400BodypartNew(int type, struct X400Bodypart **bpp)
Create a new body part object.
int X400msMsgSend(struct X400msMessage *mp)
Send message object.
#define X400_E_INT_ERROR
Definition: x400_att.h:58
#define X400_S_BODY_DATA
Definition: x400_att.h:1170
int X400msMsgAddAttachment(struct X400msMessage *mp, int type, const char *string, size_t length)
Add attachment to the message.
int X400msOpen(int type, const char *oraddr, const char *dirname, const char *credentials, const char *pa, int *messages, struct X400msSession **spp)
Open a session to a Message Store (P7) or MTA (P3) in synchronous mode.
#define X400_S_SEC_IDENTITY
Definition: x400_att.h:554
#define X400_S_FTBP_CONTENT_DESCRIPTION
Definition: x400_att.h:1200
int X400msSetStrDefault(struct X400msSession *sp, int paramtype, const char *value, size_t length)
Set a default string parameter value in a session.
int X400msMsgAddBodypart(struct X400msMessage *mp, struct X400Bodypart *bp)
#define X400_S_SECURITY_LABEL
Definition: x400_att.h:1348
int X400BodypartAddIntParam(struct X400Bodypart *bp, int paramtype, int value)
Add integer-valued parameter to the body part.
int X400msClose(struct X400msSession *sp)
Close a X400 Session.
int X400msMsgAddIntParam(struct X400msMessage *mp, int paramtype, int value)
Add integer-valued parameter to the message.
#define X400_T_BINARY
Definition: x400_att.h:825
int X400msRecipAddIntParam(struct X400Recipient *rp, int paramtype, int value)
Add integer-valued parameter to the message.
int X400msRecipAddStrParam(struct X400Recipient *rp, int paramtype, const char *value, size_t length)
Add string-valued parameter to the message.
#define X400_S_DIRECTORY_NAME
Definition: x400_att.h:397
#define X400_N_PRIORITY
Definition: x400_att.h:422
int X400msRecipNew(struct X400msMessage *mp, int type, struct X400Recipient **rpp)
Add new recipient to a message.
#define X400_T_ISO8859_1
Definition: x400_att.h:809
#define X400_B_SEC_GEN_MESSAGE_TOKEN
Definition: x400_att.h:1426
const char * X400msError(int error)
Obtain a string describing the meaning of the given error code.
#define X400_T_IA5TEXT
Definition: x400_att.h:799
#define X400_S_FTBP_CREATION_DATE
Definition: x400_att.h:1206
#define X400_S_FTBP_MODIFICATION_DATE
Definition: x400_att.h:1209
#define X400_S_SEC_IDENTITY_DN
Definition: x400_att.h:563
#define X400_RECIP_STANDARD
Definition: x400_att.h:341
#define X400_N_MMTS_PRIORITY_QUALIFIER
Definition: x400_att.h:473
int X400msMsgNew(struct X400msSession *sp, int type, struct X400msMessage **mpp)
Creates new message.
#define X400_S_CONTENT_IDENTIFIER
Definition: x400_att.h:414
#define X400_S_SEC_IDENTITY_PASSPHRASE
Definition: x400_att.h:560
#define X400_N_PROOF_OF_DEL_REQ
Definition: x400_att.h:978
#define X400_E_NOERROR
Definition: x400_att.h:46
#define X400_N_REPORT_REQUEST
Definition: x400_att.h:654
#define X400_S_EXTERNAL_CONTENT_TYPE
Definition: x400_att.h:447
X400 MA/MS (P3/P7) Interface.
#define X400_N_FTBP_OBJECT_SIZE
Definition: x400_att.h:1215
#define X400_N_MSGTOK_SEQ_NUM
Definition: x400_att.h:1443
#define X400_B_SEC_CONTENT_INTEGRITY_CHECK
Definition: x400_att.h:1432
#define X400_S_SEC_IDENTITY_FILE
Definition: x400_att.h:578
#define X400_N_S4406
Definition: x400_att.h:599
#define X400_S_FTBP_FILENAME
Definition: x400_att.h:1203
#define X400_T_FTBP
Definition: x400_att.h:834
#define X400_S_SUBJECT
Definition: x400_att.h:723
#define X400_N_NOTIFICATION_REQUEST
Definition: x400_att.h:676
int X400msTestSecurityEnv(struct X400msSession *sp)
Test the default Security Environment.
int X400msMsgAddStrParam(struct X400msMessage *mp, int paramtype, const char *value, size_t length)
Add string-valued parameter to the message.
int X400BodypartAddStrParam(struct X400Bodypart *bp, int paramtype, const char *value, size_t length)
Add string-valued parameter to the body part.
#define X400_N_PRECEDENCE
Definition: x400_att.h:686
#define X400_MSG_MESSAGE
Definition: x400_att.h:29
#define X400_E_NOMEMORY
Definition: x400_att.h:52
#define X400_E_SYSERROR
Definition: x400_att.h:49
#define X400_B_SEC_GEN_MOAC
Definition: x400_att.h:557
#define X400_S_OR_ADDRESS
Definition: x400_att.h:349
int X400msMsgDelete(struct X400msMessage *mp, int retain)
Delete message object.