//Sample code file: var/ndk/webBuildengine/tmp/viewable_samples/ce523e3a-5871-4fa6-9227-e51b7969ef46/CreateCA.cpp

//Warning: This code has been marked up for HTML

/***************************************************************************
 Copyright (c) 1998-2002 Novell, Inc.  All Rights Reserved.

 THIS WORK IS SUBJECT TO U.S. AND INTERNATIONAL COPYRIGHT LAWS AND
 TREATIES.  USE AND REDISTRIBUTION OF THIS WORK IS SUBJECT TO THE 
 LICENSE AGREEMENT ACCOMPANYING THE SOFTWARE DEVELOPMENT KIT (SDK)
 THAT CONTAINS THIS WORK.

 Pursuant to the SDK License Agreement, Novell hereby grants to 
 Developer a royalty-free, non-exclusive license to include the
 sample code AES.C and derivative binaries in its product.
 Novell grants to Developer worldwide distribution rights to market,
 distribute or sell the sample code AES.C and derivative
 binaries as a component of Developer's product(s).  Novell shall 
 have no obligations to Developer or Developer's customers with 
 respect to this code.

DISCLAIMER:

   Novell, Inc. makes no representations or warranties with respect
to the contents or use of this code, and specifically disclaims any
express or implied warranties of merchantability or fitness for any
particular purpose.  Further, Novell, Inc. reserves the right to revise
this publication and to make changes to its content, at any time,
without obligation to notify any person or entity of such revisions or
changes.

   Further, Novell, Inc. makes no representations or warranties with
respect to any software, and specifically disclaims any express or
implied warranties of merchantability or fitness for any particular
purpose.  Further, Novell, Inc. reserves the right to make changes to
any and all parts of the software, at any time, without obligation to
notify any person or entity of such changes.                          

***************************************************************************/
#ifdef WIN32
#   include <windows.h>
#endif

#include "npki.h"
#include "pkierr.h"

#define SECONDS_IN_DAY 24 * 60 * 60
#define SECONDS_IN_YEARS 365 * 24 * 60 * 60

NWRCODE CreateCA(void)
{
   NWRCODE            ccode = PKI_SUCCESS;
   NPKIContext         myPKI = NPKI_INVALID_CONTEXT;
   unicode const       *organizationalCADN;
   nuint32             signatureAlgorithms;
   nuint32             keyGenerationAlgorithms;
   nuint32             maxValidFromTime;
   nuint32             maxValidToTime;
   nuint32             currentServerTime;
   nuint32             maxSignKeySize;
   
   // user/system infomation   

   unicode            myTree[]   = {'T','E','S','T',0};
   unicode            myUser[]   = {'A','d','m','i','n','.','n','o','v','e','l','l',0};
   char               password[]   = {'t','e','s','t',0};
   char*               startIPAddress = "192.168.0.2";
   unicode            hostServerDN[] = {'T','e','s','t','5','1','.','n','o','v','e','l','l',0};
   unicode            cAName[] = {'O','r','g','a','n','i','z','a','t','i','o','n','a','l',' ','C','A',0};
   
   // certificate info

   NPKI_Extension    basicConstraints = {PKI_EXTENSION_INCLUDE | X509_BASIC_CONSTRAINTS_CA, 0};
   NPKI_Extension    keyUsage;
   nuint16            caKeyUsage = X509_KEY_USAGE_KEY_CERT_SIGN | X509_KEY_USAGE_CRL_SIGN;
   unicode            subjectDN[] = {'.','O','U','=','O','r','g','a','n','i','z','a','t','i','o','n','a','l',' ','C','A','.','O','=','C','o','m','p','a','n','y',' ','N','a','m','e',0};
   

   ccode = NPKICreateContext(&myPKI);
   if (ccode != PKI_SUCCESS)
   {
      goto ERR_EXIT;
   }
   
   // Set the tree name, this is the tree we will make all calls to.

     ccode = NPKISetTreeName(myPKI, myTree);    
   if (ccode != PKI_SUCCESS)
   {
      goto ERR_EXIT;
   }

   ccode = NPKIConnectToIPAddress(myPKI, 0, 0, startIPAddress,   NULL,   NULL);

   // Login in

   ccode = NPKIDSLogin(myPKI, myUser, password);
   if (ccode != PKI_SUCCESS)
   {
      goto ERR_EXIT;
   }

   // Check to see if an Organiztional Certificate Authority alread exists

   ccode = NPKIFindOrganizationalCA(myPKI, &organizationalCADN);
   if (ccode == PKI_SUCCESS) // one already exists

   {
      goto ERR_EXIT;
   }
   
   ccode = NPKIGetServerUTCTime
   (
      myPKI,
      hostServerDN, 
      &currentServerTime
   );
   if (ccode != PKI_SUCCESS)
   {
      goto ERR_EXIT;
   }
   currentServerTime-= (2 * SECONDS_IN_DAY);  // subtract 2 days to avoid possible time sync problems 


   ccode = NPKIGetServerInfo
   (
      myPKI, 
      hostServerDN, 
      PKI_CA_INFO, 
      &keyGenerationAlgorithms, 
      &signatureAlgorithms,
      &maxValidFromTime,
      &maxValidToTime,
      NULL,
      NULL,
      NULL,
      NULL,
      NULL
   );   
   if (ccode != PKI_SUCCESS)
   {
      goto ERR_EXIT;
   }

   if (!(keyGenerationAlgorithms & PKI_RSA_ALGORITHM)) 
   {
      ccode = PKI_E_ALGORITHM_NOT_SUPPORTED;
      goto ERR_EXIT;
   }
   
   if (!(signatureAlgorithms & PKI_SIGN_WITH_RSA_AND_SHA1))
   {
      ccode = PKI_E_ALGORITHM_NOT_SUPPORTED;
      goto ERR_EXIT;
   }

   ccode = NPKIGetAlgorithmInfo
   (
      myPKI,
      PKI_RSA_ALGORITHM, 
      NULL,
      &maxSignKeySize,
      NULL,
      NULL,                      
      NULL    
   );      
   if (ccode != PKI_SUCCESS)
   {
      goto ERR_EXIT;
   }
   
  // Validity period should probably be about 10 years

   if (maxValidFromTime < currentServerTime)
      maxValidFromTime = currentServerTime;
      
   if (maxValidToTime > currentServerTime + (10 * SECONDS_IN_YEARS)) // approx 10 years -- no leap calculations

      maxValidToTime = currentServerTime + (10 * SECONDS_IN_YEARS);
      
#ifndef HI_LO_MACH_TYPE // The key usage needs to be in Big Endian so swap

   {                     // the byte ordering if we are not on a HI LO machine type

      nuint16   newValue = 0;
      nuint8   *oldValuePtr = (nuint8 *)&caKeyUsage;
      nuint8   *newValuePtr = (nuint8 *)&newValue;
      
      newValuePtr[0] = oldValuePtr[1];
      newValuePtr[1] = oldValuePtr[0];
      caKeyUsage = newValue;
   }
#endif
   
   keyUsage.flags = PKI_EXTENSION_INCLUDE;  // Setup the key usages extension

   keyUsage.length = sizeof(caKeyUsage);
   keyUsage.value = (nuint8 *) &caKeyUsage;
   
   ccode = NPKICreateOrganizationalCA
   (
      myPKI,
      hostServerDN,
      cAName,
      PKI_RSA_ALGORITHM, 
      maxSignKeySize, 
      subjectDN,
      PKI_SIGN_WITH_RSA_AND_SHA1,
      DEFAULT_YEAR_ENCODING, 
      maxValidFromTime,
      maxValidToTime,
      PUBLIC_KEY_ORGANIZATIONAL_CA,
      PRIVATE_KEY | PRIVATE_KEY_EXTRACTABLE,
      &keyUsage, 
      &basicConstraints, 
      NULL,
      NULL,
      NULL,
      &organizationalCADN,
      0, // retryFlag

      NULL,
      NULL
   );
   if (ccode != PKI_SUCCESS)
   {
      int count = 0;
      
      while (ccode == -601 && count < 5)  // we may need to retry because of a possible eDir sync error

      {
         count++;
         Sleep(1000*count); // DWORD dwMilliseconds 

         
         ccode = NPKICreateOrganizationalCA
         (
            myPKI,
            hostServerDN,
            cAName,
            PKI_RSA_ALGORITHM, 
            maxSignKeySize, 
            subjectDN,
            PKI_SIGN_WITH_RSA_AND_SHA1,
            DEFAULT_YEAR_ENCODING, 
            maxValidFromTime,
            maxValidToTime,    
            PUBLIC_KEY_ORGANIZATIONAL_CA,
            PRIVATE_KEY | PRIVATE_KEY_EXTRACTABLE,
            &keyUsage, 
            &basicConstraints, 
            NULL,
            NULL,
            NULL,
            &organizationalCADN,
            1, // retryFlag

            NULL,
            NULL
         );
      }
   }
   
ERR_EXIT:
   NPKIDSLogout (myPKI);

   if (myPKI != NPKI_INVALID_CONTEXT)
      NPKIFreeContext(myPKI);

   return ccode;
}