Skip to content

CMP extension to OpenSSL, incremental PR chunk 1: CRMF API#7328

Closed
DDvO wants to merge 5 commits intoopenssl:masterfrom
mpeylo:cmp_incremental
Closed

CMP extension to OpenSSL, incremental PR chunk 1: CRMF API#7328
DDvO wants to merge 5 commits intoopenssl:masterfrom
mpeylo:cmp_incremental

Conversation

@DDvO
Copy link
Contributor

@DDvO DDvO commented Sep 28, 2018

Certificate Management Protocol (CMP, RFC 4210) extension to OpenSSL.
Also includes CRMF (RFC 4211) and HTTP transfer (RFC 6712).

CMP and CRMF functionality added to libcrypto, and the cmp app to the openssl CLI.
Adds extensive man pages and tests. Integration into build scripts.

Incremental pull request as suggested by @mattcaswell: #6811 (comment) and recently agreed by email.

Initial chunk consists of the CRMF API
as declared in the header file include/openssl/crmf.h
and its documentation in doc/man3/OSSL_CRMF_*.pod

Checklist
  • documentation is added or updated
  • tests are added or updated

@DDvO
Copy link
Contributor Author

DDvO commented Sep 28, 2018

The next chunk is going to be the CRMF implementation, after we have received reviewers' feedback on the CRMF API and dealt with it.

@DDvO
Copy link
Contributor Author

DDvO commented Sep 28, 2018

In case one wonders: the CI build failures automatically reported below are just due to include/openssl/crmferr.h and the implementations of the functions declared in include/openssl/crmf.h not yet being part of the PR.

Copy link
Member

@mattcaswell mattcaswell left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some initial thoughts only. I've only reviewed the header file so far.

int OSSL_CRMF_MSG_set1_regCtrl_authenticator(OSSL_CRMF_MSG *msg,
ASN1_UTF8STRING *auth);
int OSSL_CRMF_MSG_set1_regCtrl_pkiPublicationInfo(OSSL_CRMF_MSG *msg,
OSSL_CRMF_PKIPUBLICATIONINFO *pi);
Copy link
Member

@mattcaswell mattcaswell Sep 28, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So I can use the OSSL_CRMF_PKIPUBLICATIONINFO object here. I see the DECLARE_ASN1_FUNCTIONS macro above, which is going to give me *_new, *_free functions etc. But how do I populate this with any data? There seem to be no way of setting any values within this structure. The same comment applies to a number of the other objects in this header file, e.g. OSSL_CRMF_PKIARCHIVEOPTIONS, OSSL_CRMF_ENCRYPTEDVALUE.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point, I will see that those get created - although there might not be any CA-side implementation that could digest those.


/* crmf_lib.c */
int OSSL_CRMF_MSG_set1_regCtrl_regToken(OSSL_CRMF_MSG *msg,
ASN1_UTF8STRING *tok);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is only a setter for this and other fields. Should there be getters as well?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In general yes, yet this implementation focuses on the CMP (and thus CRMF) client side.
The client typically just sets these fields in its requests and does not need to read them out again.

@@ -0,0 +1,121 @@
/*
* Copyright 1995-2018 The OpenSSL Project Authors. All Rights Reserved.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a new file. Is the claim of copyright back to 1995 justified? Similarly for the Nokia and Siemens copyright claims below.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OpenSSL copyright might be a tricky question: the CMP/CRMF code builds up and loans a lot from existing OpenSSL code, which generally states copyright going back to 1995. It might be of course OK to adjust that to the earliest version of the file, which will usually be 2007?

The dates for the Nokia and Siemens copyright claims are verified; development was started in 2007.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm fine with whatever the earliest date is.

int OSSL_CRMF_MSG_set1_regInfo_certReq(OSSL_CRMF_MSG *msg,
OSSL_CRMF_CERTREQUEST *cr);

int OSSL_CRMF_MSG_set_version2(OSSL_CRMF_MSG *crm);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do we need this? RFC 4211 suggests this value SHOULD be omitted.

Copy link
Contributor

@mpeylo mpeylo Oct 2, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe if someone wants to see how a server reacts if that is set? SHOULD is not a SHALL?

If it's OpenSSL policy that such options are not there, then it will vanish. But then there might be a question how to set the optional version field? ;-)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well it's not a policy exactly. But if we're not supposed to set it according to the RFC, and it doesn't give us any benefit in setting it, then I don't really see any point in providing an API to allow people to set it.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it will be gone


/* crmf_pbm.c */
OSSL_CRMF_PBMPARAMETER *OSSL_CRMF_pbmp_new(size_t slen, int owfnid,
long itercnt, int macnid);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why long? We generally don't use long in new APIs any more. It's not particularly helpful because it may not be any bigger than int. Either use int (which we require to be at least 4 bytes in size on all our platforms), or use a int64_t if you require a larger type. Same comment applies to other uses of long in this header.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for pointing that out.

Probably historic reasons: I think when that was written, ASN1_INTEGER_set() and ASN1_INTEGER_get() were the only available options. I replace them with their int64_t counterparts. The changes will appear soon, have already sent them for quality review before merging.

Copy link
Member

@mattcaswell mattcaswell left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've now reviewed the rest of this PR. A few more comments below.


=head1 COPYRIGHT

Copyright 2007-2018 The OpenSSL Project Authors. All Rights Reserved.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just querying this copyright date again since this is a new file.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm still somewhat unsure what dates to put for OpenSSL Project Authors copyright. Basically everything is fine for me.

Options are likely:

  • first version of the file (we can find out from Sourceforge / Github)
  • first version / copyright of content somehow used or significantly in the file (that might be 2007 or 1995)
  • official / successful submission to the project (that might be 2018 or realistically 2019)

For Nokia (c) in source files, it will usually start 2007 (2015 for Siemens) as that was when content was created which eventually ended up / directly influenced in most files.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm also fine with any of these options.
My suggestion would be to simply put in all files:

Copyright 2007-2018 The OpenSSL Project Authors. All Rights Reserved.


OSSL_CRMF_ENCRYPTEDVALUE_get1_encCert() decrypts the certificate in the given
encryptedValue B<ecert>, using the private key B<pkey>.
This is needed for the indirect PoP method as in RFC 4210 section 5.2.8.2.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Although it is implied from the get0/get1 name, not everyone is familiar with that particular OpenSSL idiom so we should explicitly state the memory management semantics for each getter/setter. (Comment applies here and in all the other pod files)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've taken care of this (for all CRMF doc files), also regarding set0 vs. set1.


=head1 DESCRIPTION

OSSL_CRMF_MSG_set1_regInfo_utf8Pairs() adds the cutf8Pairs regInfo to the given
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

cutf8Pairs? Typo? RFC4211 says that this can appear multiple times in the regInfo. Is this possible with this API?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Typo, good catch.

Yes, the code allows to set multiple instances of the utf8Pairs control to be set by calling that function multiple times. I realized that this is also possible for certReq, where the RFC states that there can only be one (which makes sense due to its nature- while using non-normative language).

I would describe this in a NOTES section to the man page. I believe that this is sufficient, and it does not require explicit enforcement by the API, as as nobody will ever be able to use this functions without closely investigating in the RFC what they are for in the first place.

=head1 NOTES

Calling the functions multiple times adds multiple instances of the control in
question to the regInfo structure of the given B<msg>. However RFC RFC 4211
only expects multiple instances of utf8Pairs in one regInfo structure, but not
for certReq.

Does this make sense?

structure with new a random salt of given length B<saltlen>, OWF (one-way
function) NID B<owfnid>, iteration count B<itercnt>, and MAC NID B<macnid>.

The iteration count is enforced to be at least 100, as stipulated by RFC 4211.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Drop this sentence. You already said it above.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It will be gone

=head1 NOTES

The OWF (one-way function) and for the MAC (message authentication code) may be
any with an NID defined in B<openssl/objects.h>,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: "a NID"

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thanks

unsiged char *msg = "Hello";
unsiged char *sec = "SeCrEt";
unsiged char *mac = NULL;
unsiged int maclen;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Typo: unsigned

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

good eyes, thanks

@DDvO
Copy link
Contributor Author

DDvO commented Oct 12, 2018

We have meanwhile reacted to all of Matt's review comments and provided an update with our respective fixes.

Copy link
Member

@mattcaswell mattcaswell left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks ok to me. Needs a second review from @openssl/committers.

I'm not sure how best to handle this. Until we have the implementation half of this, it probably shouldn't really be merged. On the other hand that will complicate the review of the implementation PR because it will have to include all the commits from this PR.

@DDvO
Copy link
Contributor Author

DDvO commented Oct 15, 2018

Pleased to hear.
I can squash all hitherto commits into one, will this help?

@mattcaswell
Copy link
Member

I can squash all hitherto commits into one, will this help?

Yes - lets do that.

@DDvO
Copy link
Contributor Author

DDvO commented Oct 17, 2018

Oops, I had overlooked your swift response.
Just did the squashing; in this branch there were anyway just two commits regarding the CRMF API.

@mattcaswell
Copy link
Member

Still looking for a second reviewer for this. Ping @openssl/committers

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Aehm, sorry, but "popo" is the german word for butt.
Could we please have another name?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

:-) That's funny!

Actually though it is consistently called popo in the RFC!!

Copy link
Contributor

@mspncp mspncp Oct 17, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually though it is consistently called popo in the RFC!!

Actually they don't use it consistently: I counted only 23 POPOs vs 71-23 = 48 POPs.

curl https://www.ietf.org/rfc/rfc4210.txt | tr ' ' '\n' | grep POP | wc -l
71
curl https://www.ietf.org/rfc/rfc4210.txt | tr ' ' '\n' | grep POPO | wc -l
23

So why not use POP instead of POPO?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the waned to have a prove that the joke is really funny...

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Both Martin and me are native German speakers.
We're aware of this accidental pun and got used to it :)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yeah, as far as the ASN.1 terms are used, its probably okay.
Honestly I had to laugh and could not stop for a while :) when I read the create_popo thing...

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yeah, as far as the ASN.1 terms are used, its probably okay.
Honestly I had to laugh and could not stop for a while :) when I read the create_popo thing...

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

B<rid>

Copy link
Contributor Author

@DDvO DDvO Oct 17, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oops; will be fixed (as well as RAVerfied -> RAVerified).

Also includes CRMF (RFC 4211) and HTTP transfer (RFC 6712)

CMP and CRMF API is added to libcrypto, and the "cmp" app to the openssl CLI.
Adds extensive man pages and tests.  Integration into build scripts.

Incremental pull request based on OpenSSL commit 1362190 of 2018-09-26

1st chunk: CRMF API (include/openssl/crmf.h) and its documentation (reviewed)
@DDvO
Copy link
Contributor Author

DDvO commented Oct 17, 2018

I've meanwhile provided the code portion of the CRMF implementation as the second commit.

@mattcaswell
Copy link
Member

I've meanwhile provided the code portion of the CRMF implementation as the second commit.

Personally I would remove that commit until such time as @bernd-edlinger has finished reviewing what is currently there. And then I would create it as a different PR with both the commits from here and the implementation commits so that we have a clear separation of the review history and we know exactly what is in scope for review at any one time.

@DDvO
Copy link
Contributor Author

DDvO commented Oct 17, 2018

All right, I will retract the second commit soon.
(I'm just curious to wait and see if besides the successful Travis CI build also the AppVeyor build will succeed).

@DDvO
Copy link
Contributor Author

DDvO commented Oct 17, 2018

Also AppVeyor was fine with the code :-)
As suggested by @mattcaswell, I've just removed the second commit (containing the CRMF code) such that this PR is on the CRMF API only.


=head1 RETURN VALUES

All functions returns 1 on success, 0 on error.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

return 1 on

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep

to B<si>. Consumes the B<spi> pointer.

OSSL_CRMF_MSG_set0_SinglePubInfo() sets given B<method> and PubLoction B<nm> to
B<spi>. PubLocation is optional, and therfore B<nm> may be NULL. Consumes the
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

therefore

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

int OSSL_CRMF_MSG_set_validity(OSSL_CRMF_MSG *crm, time_t from, time_t to);
int OSSL_CRMF_MSG_set_certReqId(OSSL_CRMF_MSG *crm, int rid);
int OSSL_CRMF_MSG_get_certReqId(OSSL_CRMF_MSG *crm);
int OSSL_CRMF_ASN1_get_int(int *pr, const ASN1_INTEGER *a);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What does this function?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, this is a new function I forgot to document so far. It's basically like ASN1_INTEGER_get_int64(), actually calling it, but with range checks according its result type int. It is used both in the CRMF and CMP sub-libraries. I'll add the doc.

BTW, this rather general function could also be moved (with adapted name) to crypto/asn1/a_int.c. I'll add a TODO.

# define OSSL_CRMF_POPOPRIVKEY_AGREEMAC 3
# define OSSL_CRMF_POPOPRIVKEY_ENCRYPTEDKEY 4

# define OSSL_CRMF_SUBSEQUENTMESSAGE_ENCRCERT 0
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

funny, the methods are called like encCert, rfc4210 "CertOrEncCert", rfc 4211 has "encrCert"

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Indeed.

@DDvO
Copy link
Contributor Author

DDvO commented Nov 5, 2018

@bernd-edlinger, thank you for your review of the CRMF API and doc.
My above commit addressed all your improvement hints. Is this now fine for you or do you see anything else that we should improve before we provide the actual CRMF code?

Copy link
Member

@bernd-edlinger bernd-edlinger left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@DDvO DDvO changed the title CMP (RFC 4210) extension to OpenSSL, incremental PR CMP extension to OpenSSL, incremental PR chunk 1 Nov 16, 2018
@DDvO
Copy link
Contributor Author

DDvO commented Nov 16, 2018

Nice that we meanwhile have both approvals :)

I've just provided the second chunk of our incremental PR in #7646.

@mattcaswell
Copy link
Member

I've just applied the "hold" label on this, so that no one attempts to merge it until chunk 2 is also ready.

@DDvO DDvO changed the title CMP extension to OpenSSL, incremental PR chunk 1 CMP extension to OpenSSL, incremental PR chunk 1: CRMF API Nov 16, 2018
@mattcaswell mattcaswell added approval: done This pull request has the required number of approvals and removed hold labels Mar 12, 2019
@mattcaswell
Copy link
Member

Now that #7646 is approved, I pushed this one.

levitte pushed a commit that referenced this pull request Mar 12, 2019
Also includes CRMF (RFC 4211) and HTTP transfer (RFC 6712)

CMP and CRMF API is added to libcrypto, and the "cmp" app to the openssl CLI.
Adds extensive man pages and tests.  Integration into build scripts.

Incremental pull request based on OpenSSL commit 1362190 of 2018-09-26

1st chunk: CRMF API (include/openssl/crmf.h) and its documentation (reviewed)

Reviewed-by: Bernd Edlinger <[email protected]>
Reviewed-by: Matt Caswell <[email protected]>
(Merged from #7328)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

approval: done This pull request has the required number of approvals

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants