1
/**************************************************************************
2
*** COPYRIGHT (c) 2002 by TransNexus, Inc. ***
4
*** This software is property of TransNexus, Inc. ***
5
*** This software is freely available under license from TransNexus. ***
6
*** The license terms and conditions for free use of this software by ***
7
*** third parties are defined in the OSP Toolkit Software License ***
8
*** Agreement (LICENSE.txt). Any use of this software by third ***
9
*** parties, which does not comply with the terms and conditions of the ***
10
*** OSP Toolkit Software License Agreement is prohibited without ***
11
*** the prior, express, written consent of TransNexus, Inc. ***
13
*** Thank you for using the OSP ToolKit(TM). Please report any bugs, ***
14
*** suggestions or feedback to support@transnexus.com ***
16
**************************************************************************/
24
#include "osp/osposincl.h"
25
#include "openssl/ssl.h"
27
/* This is the "operation" parameter that is sent in each request: */
28
#define OSPC_ENROLL_OPERATION_REQ_PARAM "operation"
30
/* These are the possible values of the "operation" parameter: */
31
#define OSPC_ENROLL_OP_REQUEST_REQ_PARAM "request"
32
#define OSPC_ENROLL_OP_RETRIEVE_REQ_PARAM "retrieve"
33
#define OSPC_ENROLL_OP_CA_CERT_REQ_PARAM "getcacert"
35
/* These are the constants that may be returned in a response: */
36
#define OSPC_ENROLL_CA_CERT_RSP_PARAM "certificate"
38
/* These are also the parameters that are sent in each certificate request
41
#define OSPC_ENROLL_NONCE_REQ_PARAM "nonce"
42
#define OSPC_ENROLL_USERNAME_REQ_PARAM "username"
43
#define OSPC_ENROLL_PASSWORD_REQ_PARAM "password"
44
#define OSPC_ENROLL_DEVICEID_REQ_PARAM "device"
45
#define OSPC_ENROLL_CUSTOMERID_REQ_PARAM "customer"
46
#define OSPC_ENROLL_CERT_REQ_PARAM "request"
48
#define OSPC_ENROLL_CERT_RSP_PARAM "cert"
49
#define OSPC_ENROLL_STATUS_RSP_PARAM "status"
51
/* These signify successful and pending certificate requests, respectively: */
52
#define OSPC_ENROLL_STATUS_OK 0
53
#define OSPC_ENROLL_STATUS_PENDING 1
55
/* Denotes the failure of an enrollment request; this may happen even
56
* if there aren't any problems with the enrollment client:
58
#define OSPC_ENROLL_STATUS_FAILURE_DEFAULT 2
61
/* The possible field delimiters in a URL are an ampersand ( '&' ) and
62
* a space, which would indicate some other field. Actually, this is true
63
* for any whitespace character.
65
#define OSPC_ENROLL_FIELD_DELIMITERS "& "
67
/* The "normal" field delimiter for a url is an ampersand: */
68
#define OSPC_ENROLL_FIELD_DELIMITER "&"
70
/* This separates names and values in an url. For example,
71
* in http://www.transnexus.com/some_path/enroll?name=value&another_name=x ,
72
* the name and value in the HTTP get would be the '='.
74
#define OSPC_ENROLL_NAME_VALUE_DELIMITER "="
76
/* The content type of the message we post to the enrollment server: */
77
#define OSPC_ENROLL_CONTENT_TYPE "text/html"
79
/* What is the maximum length of the request that could be transmitted?
80
* This needs to take into account the maximum size of a
81
* RelativeDistinguishedName ( say, 2KB ), the size of a subjectPublicKeyInfo
82
* and a signature ( 512 bytes, for 2 2048-bit values ), and the size
83
* of the attributes and other cert request chaff ( say, less than 512 bytes ).
84
* If we base64-encode this, then we get a max of about 4KB.
86
#define OSPC_ENROLL_MAX_REQUEST_SIZE 4096
88
/* How long will the nonce be in bytes? */
89
#define OSPC_ENROLL_NONCE_LEN 16
97
* Given the input parameters for enrollment, setup all of the communications
98
* and structures for enrollment and then send a request to the enrollment
99
* server. The results should be stored in the ospvEnrollStatusOUt
100
* ( failed, pending, or success ) and ospvLocalCertOut ( if the request
104
OSPTENROLLPARAMS* ospvEnrollParamsIn,
105
OSPTCOMMPARAMS* ospvCommParamsIn,
106
unsigned char** ospvLocalCertOut,
107
unsigned* ospvLocalCertLenOut,
108
unsigned* ospvEnrollStatusOut
111
/* Given the enrollment parameters, base64-decode the CACertB64 parameter
112
* of the enrollment parmaeters and place the binary CA certificate in the
113
* CACert field of the enrollment parameters instead.
115
* Input: pointer to the enrollment parameters, which should contain a pointer
116
* the base64-encoded CA certificate and its length, as well as pointers
117
* to the binary CA certificate and its length ( which will initially
120
* Output: OSPC_ERR_NO_ERROR is returned if there are no problems, or
121
* a non-OSPC_ERR_NO_ERROR value is returned. If everything is
122
* successful, then the CACertB64 field should be populated as well.
124
int OSPPBase64DecodeCACert(
125
OSPTENROLLPARAMS* ospvEnrollParamsIn
129
* Create an enrollment request for requesting or retrieving a certificate,
130
* send the request to the enrollment server ( using the communications
131
* manager passed in ); extract the status and certificate from the
132
* response, validate the certificate, and return the certificate.
134
int OSPPEnrollDevice (
135
OSPTCOMM* ospvCommMgr,
136
OSPTMSGINFO* ospvEnrollMsg,
137
OSPTASN1OBJECT* ospvRequestPublicKeyIn,
138
unsigned* ospvEnrollStatusOut,
139
unsigned char** ospvCertOut,
140
unsigned* ospvCertLenOut
144
* Given a certificate for a device that has been received, validate it
145
* against the public key used ( to be added ), the CA certificate that
146
* we expected to sign it, and its general construction. The certificate
147
* is placed in *ospvCertOut.
149
int OSPPValidateDeviceCert (
151
OSPTASN1OBJECT* ospvRequestPublicKeyIn,
152
unsigned char* ospvCertB64In,
153
unsigned char** ospvCertOut,
154
unsigned* ospvCertLenOut
158
int OSPPCreateEnrollmentRequestHeader(
159
OSPTMSGINFO* ospvEnrollmentReqMsgInfo
162
int OSPPCreateEnrollmentRequestBody(
163
unsigned char** ospvRequestBfrOut,
164
OSPTENROLLPARAMS* ospvEnrollParamsIn
168
* Create a nonce value that will serve for both stronger encryption ( to
169
* eliminate known-ciphertext attacks ) and for preventing flooding at the
170
* server. This isn't required by an enrollment server, but it is recommended.
172
* Input: references to the nonce's character string and the nonce's length;
173
* both are set on output.
175
* Output: success in generating the nonce: OSPC_ERR_NO_ERROR if successful,
176
* another value otherwise. *ospvNonce should be allocated a block
177
* of memory whose length is specified by ospvNonceLenIn. Note that
178
* existing memory will not be used.
181
int OSPPFillBufWithRandomBytes(
182
unsigned char* ospvNonce,
183
unsigned* ospvNonceLenOut,
184
unsigned ospvNonceLenIn
187
/* Check all of the enrollment parameters for any problems that might cause
188
* it to be rejected by an enrollment server. We'll check that the
189
* username and password are alphanumeric, that the customer and device ids
190
* are numeric, and that the base64-encoded certificate request exists
191
* ( the contents of the base64-encoded certificate request are validated
192
* elsewhere. ) We'll get an error if any of these values are empty or null.
194
* Input: reference to the enrollment parameters
196
* Output: OSPC_ERR_NO_ERROR if all of the parameters are non-null, non-empty,
197
* and have the appropriate type. Otherwise, an error code other
198
* than OSPC_ERR_NO_ERROR will be returned.
200
int OSPPCheckEnrollmentParams (
201
OSPTENROLLPARAMS* ospvEnrollParams
205
* Given a pointer to some enrollment parameters, check the validity of each
206
* parameter for requesting a certificate. This function returns an error
207
* if any of the values are invalid.
209
* Input: pointer to an enrollment parameter list; there is only one structure,
210
* and the use of the reference is done for the sake of efficiency.
212
* Output: OSPC_ERR_NO_ERROR if all of the parameters can be used in a cert
213
* request; otherwise, an error is returned.
215
int OSPPCheckEnrollmentRequestParams(
216
OSPTENROLLPARAMS* ospvEnrollParams
219
/* Given a pointer to a string to write, and a pointer to its length, and
220
* the length of a nonce to generate, generate a nonce and place it in the
221
* output string and its referenced length. The nonce will be binary, not
224
* This function will use OSPPFillBufWithRandomBytes, which in turn
225
* relies on OSPPUtilGetRandom, for generating the random bytes of the nonce.
226
* Since OSPPUtilGetRandom doesn't rely on anything special for the
227
* entropy of these random values, it would be best to either modify
228
* OSPPUtilGetRandom or just pass the value of the nonce in ( so that we
229
* don't generate it here. )
231
* Input: reference to a string and its length to write to, as well as a
232
* length that specifies how long the nonce should be.
234
* Output: OSPC_ERR_NO_ERROR if there aren't any problems; in this case,
235
* the *ospvNonceOut should be non-null and *ospvNonceLenOut should
236
* specify its length. Otherwise, an error code other than
237
* OSPC_ERR_NO_ERROR will be returned if a problem comes up. In this
238
* case, *ospvNonceOut should be OSPC_OSNULL and *ospvNonceLenOut
239
* should be 0 ( but this isn't guaranteed, especially if
240
* ospvNonceOut or ospvNonceLenOut were OSPC_OSNULL to begin with. )
243
unsigned char** ospvNonceOut,
244
unsigned* ospvNonceLenOut,
245
unsigned ospvNonceLenIn
249
* Given a character string that will eventually be sent to an enrollment
250
* server as part of a MsgInfo's Request, add a name-value pair that reflects
251
* an enrollment parameter.
253
* Input: the request's character string, plus the k
257
int OSPPAddNameValuePair(
258
unsigned char* ospvDestStr,
259
unsigned char* ospvName,
260
unsigned ospvNameLen,
261
unsigned char* ospvValue,
262
unsigned ospvValueLen,
263
unsigned ospvPrependAmpersand
266
/* Given a source string of characters, URL-encode it and append it to
267
* the destination string:
269
int OSPPAppendUrlEncodedString (
270
unsigned char* destStr,
271
unsigned char* srcStr,
276
* Given a MessageInfo structure, extract the status from the "status=" field
277
* that's contained in the Response field. If the status field cannot be found,
278
* then this function will return an error.
280
int OSPPGetStatusFromResponse (
281
const OSPTMSGINFO* ospvMsgInfo,
282
unsigned* ospvEnrollStatusOut
286
* Given a MessageInfo structure, extract the certificate from it. There
287
* is no need to check the base64 encoding of the certificate or any other
288
* structural constraints.
290
int OSPPGetCertificateFromResponse (
291
const OSPTMSGINFO* ospvMsgInfo,
292
unsigned char* ospvCertOut,
293
unsigned* ospvCertLenOut
297
* Given the CA certificate and a certificate that is supposedly for the
298
* router, check its validity. That is, decode the base64 encoding of the
299
* certificate, make sure that it's an X.509 cert, that it has the correct
300
* version ( 2, to indicate a version 3 cert ); and that it's signed by
301
* the CA. This should also include something for checking the public key
304
int OSPPValidateCert (
305
const unsigned char* ospvCACertIn,
306
const unsigned char* ospvCertIn,
307
const unsigned ospvCertLenIn,
308
const OSPTASN1OBJECT* ospvSubjectPublicKeyInfoIn,
309
OSPTASN1OBJECT* ospvCertOut
313
* Compare the two ASN1 objects. Returns OSPC_ERR_NO_ERROR if they're the
314
* same, and a non-zero value otherwise.
317
* ospvLHSObject: a pointer to an ASN1 Object ( the LeftHand Side )
318
* ospvRHSObject: a pointer to an ASN1 Object ( the RightHand Side )
321
* OSPC_ERR_NO_ERROR if the two are the same, or some other value otherwise.
323
* Errors: Errors will be returned when
324
* o at least one of the parameters is null ( OSPC_ERR_ENROLL_INVALID_PARAMS )
325
* o the two have different lengths ( OSPC_ERR_ENROLL_LENGTH_MISMATCH );
326
* o the two have different contents ( OSPC_ERR_ENROLL_CONTENT_MISMATCH );
328
int OSPPASN1Compare (
329
OSPTASN1OBJECT* ospvLHSObject,
330
OSPTASN1OBJECT* ospvRHSObject
335
* This is for constructing the enrollment request that is sent to the
336
* enrollment server; the output is an OSPTMSGINFO structure that
339
* Input: A pointer to the enrollment parameters and to the MessageInfo that
340
* contains the parameters for the enrollment request.
342
* Output: The OSPTMSGINFO should contain all of the information necessary
343
* for transmitting a request to the enrollment server. In this case,
344
* the return value will be OSPC_ERR_NO_ERROR. If something
345
* goes wrong, then the return value will be something other than
346
* OSPC_ERR_NO_ERROR. In that case, there is no guarantee about what
347
* the OSPTMSGINFO* structure will contain.
349
int OSPPConstructEnrollmentRequest (
350
OSPTENROLLPARAMS* ospvEnrollParamsIn,
351
OSPTMSGINFO* ospvMsgInfoOut
355
* Given a base64 encoding of a certificate request, retrieve the
356
* subjectPublicKeyInfo from that certificate request and store it in the
357
* given ASN.1 element info's placeholder.
359
* Input: base64 certificate request
360
* ( unsigned char* ospvBase64CertReq )
362
* Output: *ospvPublicKeyInfoOut should, if successful, contain the
363
* subjectPublicKeyInfo of the certificate request. If not, then
364
* an errorcode should be returned.
366
* Errors: Errorcodes other than OSPC_ERR_NO_ERROR are returned when:
367
* o either parameter is null;
368
* o memory cannot be allocated for ephemeral variables;
369
* o the certificate request is improperly base64 encoded;
370
* o the certificate request is invalid ( i.e., the subjectPublicKeyInfo
371
* could not be found in the desired location );
373
int OSPPGetPublicKeyInfoFromCertReq(
374
unsigned char* ospvBase64CertReq,
375
OSPTASN1OBJECT* ospvPublicKeyInfoOut
378
/* Given a character string, make sure that it's valid: it's non-null,
379
* and has nothing but ascii characters:
381
int OSPPValidateAsciiString(
382
unsigned char* ospvAlnumStr
385
/* Given a string of digits, make sure that it's valid: it's non-null,
386
* and has nothing but digits.
388
int OSPPValidateDigitString(
389
unsigned char* ospvDigitStr
392
/* Given an ASN1 object that represents an X.509 certificate, store its
393
* subjectPublicKeyInfo in the outbound ospvPublicKeyOut structure.
394
* This subjectPublicKeyInfo will be compared against what we get from
395
* the server in the form of a certificate; if they match, then the
396
* certificate may be ok - otherwise, the certificate is bogus.
398
* Input: references to the input certificate and the outgoing
399
* subjectPublicKeyInfo
401
* Output: If the subjectPublicKeyInfo can be found, then it should be
402
* stored in *ospvPublicKeyOut and the return value will be
403
* OSPC_ERR_NO_ERROR. Otherwise, the return value will be
404
* something other than OSPC_ERR_NO_ERROR.
406
int OSPPGetPublicKeyInfoFromCert(
407
OSPTASN1OBJECT* ospvCertIn,
408
OSPTASN1OBJECT* ospvPublicKeyOut
411
/* Given a binary string that represents a PKCS#10 request, create an
412
* ASN1 object that contains the subjectPublicKeyInfo of the certificate
413
* request. The subjectPublicKeyInfo is found as follows:
415
* SEQUENCE CertificateRequest
416
* SEQUENCE certificateRequestInfo
418
* SEQUENCE subjectName
419
* SEQUENCE subjectPublicKeyInfo
420
* SEQUENCE attributes
421
* OID signatureAlgorithm
422
* BIT STRING signature
424
* We'll use the ASN1 module from the OSP to decode the binary string
425
* and extract the public key from the certificate request.
427
* Input: string representing a PKCS#10 certificate request, and a pointer
428
* to an ASN1 object for storing its subjectPublicKeyInfo.
430
* Output: the subjectPublicKeyInfo should be found, in which case we'll
431
* return OSPC_ERR_NO_ERROR. Otherwise, a different error code will
434
int OSPPGetPublicKeyInfoFromCertReq(
435
unsigned char* ospvCertReqIn,
436
OSPTASN1OBJECT* ospvPublicKeyOut
439
/* Cleanup the communications manager: its HTTP connections, security manager,
440
* and the communications manager itself. The only way that this function
441
* will return an error is if the communications manager passed in for deletion
444
* Input: reference to the communications manager pointer to be deleted.
446
int OSPPEnrollCleanupCommMgr (
447
OSPTCOMM** ospvCommMgrIn