cjson
fuzzing
inputs
test1 test10 test11 test2 test3 test3.bu test3.uf test3.uu test4 test5 test6 test7 test8 test9library_config
cJSONConfig.cmake.in cJSONConfigVersion.cmake.in libcjson.pc.in libcjson_utils.pc.in uninstall.cmaketests
inputs
test1 test1.expected test10 test10.expected test11 test11.expected test2 test2.expected test3 test3.expected test4 test4.expected test5 test5.expected test6 test7 test7.expected test8 test8.expected test9 test9.expectedjson-patch-tests
.editorconfig .gitignore .npmignore README.md cjson-utils-tests.json package.json spec_tests.json tests.jsonunity
auto
colour_prompt.rb colour_reporter.rb generate_config.yml generate_module.rb generate_test_runner.rb parse_output.rb stylize_as_junit.rb test_file_filter.rb type_sanitizer.rb unity_test_summary.py unity_test_summary.rb unity_to_junit.pydocs
ThrowTheSwitchCodingStandard.md UnityAssertionsCheatSheetSuitableforPrintingandPossiblyFraming.pdf UnityAssertionsReference.md UnityConfigurationGuide.md UnityGettingStartedGuide.md UnityHelperScriptsGuide.md license.txtexamples
unity_config.hcurl
.github
scripts
cleancmd.pl cmp-config.pl cmp-pkg-config.sh codespell-ignore.words codespell.sh distfiles.sh pyspelling.words pyspelling.yaml randcurl.pl requirements-docs.txt requirements-proselint.txt requirements.txt shellcheck-ci.sh shellcheck.sh spellcheck.curl trimmarkdownheader.pl typos.sh typos.toml verify-examples.pl verify-synopsis.pl yamlcheck.sh yamlcheck.yamlworkflows
appveyor-status.yml checkdocs.yml checksrc.yml checkurls.yml codeql.yml configure-vs-cmake.yml curl-for-win.yml distcheck.yml fuzz.yml http3-linux.yml label.yml linux-old.yml linux.yml macos.yml non-native.yml windows.ymlCMake
CurlSymbolHiding.cmake CurlTests.c FindBrotli.cmake FindCares.cmake FindGSS.cmake FindGnuTLS.cmake FindLDAP.cmake FindLibbacktrace.cmake FindLibgsasl.cmake FindLibidn2.cmake FindLibpsl.cmake FindLibssh.cmake FindLibssh2.cmake FindLibuv.cmake FindMbedTLS.cmake FindNGHTTP2.cmake FindNGHTTP3.cmake FindNGTCP2.cmake FindNettle.cmake FindQuiche.cmake FindRustls.cmake FindWolfSSL.cmake FindZstd.cmake Macros.cmake OtherTests.cmake PickyWarnings.cmake Utilities.cmake cmake_uninstall.in.cmake curl-config.in.cmake unix-cache.cmake win32-cache.cmakedocs
cmdline-opts
.gitignore CMakeLists.txt MANPAGE.md Makefile.am Makefile.inc _AUTHORS.md _BUGS.md _DESCRIPTION.md _ENVIRONMENT.md _EXITCODES.md _FILES.md _GLOBBING.md _NAME.md _OPTIONS.md _OUTPUT.md _PROGRESS.md _PROTOCOLS.md _PROXYPREFIX.md _SEEALSO.md _SYNOPSIS.md _URL.md _VARIABLES.md _VERSION.md _WWW.md abstract-unix-socket.md alt-svc.md anyauth.md append.md aws-sigv4.md basic.md ca-native.md cacert.md capath.md cert-status.md cert-type.md cert.md ciphers.md compressed-ssh.md compressed.md config.md connect-timeout.md connect-to.md continue-at.md cookie-jar.md cookie.md create-dirs.md create-file-mode.md crlf.md crlfile.md curves.md data-ascii.md data-binary.md data-raw.md data-urlencode.md data.md delegation.md digest.md disable-eprt.md disable-epsv.md disable.md disallow-username-in-url.md dns-interface.md dns-ipv4-addr.md dns-ipv6-addr.md dns-servers.md doh-cert-status.md doh-insecure.md doh-url.md dump-ca-embed.md dump-header.md ech.md egd-file.md engine.md etag-compare.md etag-save.md expect100-timeout.md fail-early.md fail-with-body.md fail.md false-start.md follow.md form-escape.md form-string.md form.md ftp-account.md ftp-alternative-to-user.md ftp-create-dirs.md ftp-method.md ftp-pasv.md ftp-port.md ftp-pret.md ftp-skip-pasv-ip.md ftp-ssl-ccc-mode.md ftp-ssl-ccc.md ftp-ssl-control.md get.md globoff.md happy-eyeballs-timeout-ms.md haproxy-clientip.md haproxy-protocol.md head.md header.md help.md hostpubmd5.md hostpubsha256.md hsts.md http0.9.md http1.0.md http1.1.md http2-prior-knowledge.md http2.md http3-only.md http3.md ignore-content-length.md insecure.md interface.md ip-tos.md ipfs-gateway.md ipv4.md ipv6.md json.md junk-session-cookies.md keepalive-cnt.md keepalive-time.md key-type.md key.md knownhosts.md krb.md libcurl.md limit-rate.md list-only.md local-port.md location-trusted.md location.md login-options.md mail-auth.md mail-from.md mail-rcpt-allowfails.md mail-rcpt.md mainpage.idx manual.md max-filesize.md max-redirs.md max-time.md metalink.md mptcp.md negotiate.md netrc-file.md netrc-optional.md netrc.md next.md no-alpn.md no-buffer.md no-clobber.md no-keepalive.md no-npn.md no-progress-meter.md no-sessionid.md noproxy.md ntlm-wb.md ntlm.md oauth2-bearer.md out-null.md output-dir.md output.md parallel-immediate.md parallel-max-host.md parallel-max.md parallel.md pass.md path-as-is.md pinnedpubkey.md post301.md post302.md post303.md preproxy.md progress-bar.md proto-default.md proto-redir.md proto.md proxy-anyauth.md proxy-basic.md proxy-ca-native.md proxy-cacert.md proxy-capath.md proxy-cert-type.md proxy-cert.md proxy-ciphers.md proxy-crlfile.md proxy-digest.md proxy-header.md proxy-http2.md proxy-insecure.md proxy-key-type.md proxy-key.md proxy-negotiate.md proxy-ntlm.md proxy-pass.md proxy-pinnedpubkey.md proxy-service-name.md proxy-ssl-allow-beast.md proxy-ssl-auto-client-cert.md proxy-tls13-ciphers.md proxy-tlsauthtype.md proxy-tlspassword.md proxy-tlsuser.md proxy-tlsv1.md proxy-user.md proxy.md proxy1.0.md proxytunnel.md pubkey.md quote.md random-file.md range.md rate.md raw.md referer.md remote-header-name.md remote-name-all.md remote-name.md remote-time.md remove-on-error.md request-target.md request.md resolve.md retry-all-errors.md retry-connrefused.md retry-delay.md retry-max-time.md retry.md sasl-authzid.md sasl-ir.md service-name.md show-error.md show-headers.md sigalgs.md silent.md skip-existing.md socks4.md socks4a.md socks5-basic.md socks5-gssapi-nec.md socks5-gssapi-service.md socks5-gssapi.md socks5-hostname.md socks5.md speed-limit.md speed-time.md ssl-allow-beast.md ssl-auto-client-cert.md ssl-no-revoke.md ssl-reqd.md ssl-revoke-best-effort.md ssl-sessions.md ssl.md sslv2.md sslv3.md stderr.md styled-output.md suppress-connect-headers.md tcp-fastopen.md tcp-nodelay.md telnet-option.md tftp-blksize.md tftp-no-options.md time-cond.md tls-earlydata.md tls-max.md tls13-ciphers.md tlsauthtype.md tlspassword.md tlsuser.md tlsv1.0.md tlsv1.1.md tlsv1.2.md tlsv1.3.md tlsv1.md tr-encoding.md trace-ascii.md trace-config.md trace-ids.md trace-time.md trace.md unix-socket.md upload-file.md upload-flags.md url-query.md url.md use-ascii.md user-agent.md user.md variable.md verbose.md version.md vlan-priority.md write-out.md xattr.mdexamples
.checksrc .gitignore 10-at-a-time.c CMakeLists.txt Makefile.am Makefile.example Makefile.inc README.md adddocsref.pl address-scope.c altsvc.c anyauthput.c block_ip.c cacertinmem.c certinfo.c chkspeed.c connect-to.c cookie_interface.c crawler.c debug.c default-scheme.c ephiperfifo.c evhiperfifo.c externalsocket.c fileupload.c ftp-delete.c ftp-wildcard.c ftpget.c ftpgetinfo.c ftpgetresp.c ftpsget.c ftpupload.c ftpuploadfrommem.c ftpuploadresume.c getinfo.c getinmemory.c getredirect.c getreferrer.c ghiper.c headerapi.c hiperfifo.c hsts-preload.c htmltidy.c htmltitle.cpp http-options.c http-post.c http2-download.c http2-pushinmemory.c http2-serverpush.c http2-upload.c http3-present.c http3.c httpcustomheader.c httpput-postfields.c httpput.c https.c imap-append.c imap-authzid.c imap-copy.c imap-create.c imap-delete.c imap-examine.c imap-fetch.c imap-list.c imap-lsub.c imap-multi.c imap-noop.c imap-search.c imap-ssl.c imap-store.c imap-tls.c interface.c ipv6.c keepalive.c localport.c log_failed_transfers.c maxconnects.c multi-app.c multi-debugcallback.c multi-double.c multi-event.c multi-formadd.c multi-legacy.c multi-post.c multi-single.c multi-uv.c netrc.c parseurl.c persistent.c pop3-authzid.c pop3-dele.c pop3-list.c pop3-multi.c pop3-noop.c pop3-retr.c pop3-ssl.c pop3-stat.c pop3-tls.c pop3-top.c pop3-uidl.c post-callback.c postinmemory.c postit2-formadd.c postit2.c progressfunc.c protofeats.c range.c resolve.c rtsp-options.c sendrecv.c sepheaders.c sessioninfo.c sftpget.c sftpuploadresume.c shared-connection-cache.c simple.c simplepost.c simplessl.c smooth-gtk-thread.c smtp-authzid.c smtp-expn.c smtp-mail.c smtp-mime.c smtp-multi.c smtp-ssl.c smtp-tls.c smtp-vrfy.c sslbackend.c synctime.c threaded.c unixsocket.c url2file.c urlapi.c usercertinmem.c version-check.pl websocket-cb.c websocket-updown.c websocket.c xmlstream.cinternals
BUFQ.md BUFREF.md CHECKSRC.md CLIENT-READERS.md CLIENT-WRITERS.md CODE_STYLE.md CONNECTION-FILTERS.md CREDENTIALS.md CURLX.md DYNBUF.md HASH.md LLIST.md MID.md MQTT.md MULTI-EV.md NEW-PROTOCOL.md PEERS.md PORTING.md RATELIMITS.md README.md SCORECARD.md SPLAY.md STRPARSE.md THRDPOOL-AND-QUEUE.md TIME-KEEPING.md TLS-SESSIONS.md UINT_SETS.md WEBSOCKET.mdlibcurl
opts
CMakeLists.txt CURLINFO_ACTIVESOCKET.md CURLINFO_APPCONNECT_TIME.md CURLINFO_APPCONNECT_TIME_T.md CURLINFO_CAINFO.md CURLINFO_CAPATH.md CURLINFO_CERTINFO.md CURLINFO_CONDITION_UNMET.md CURLINFO_CONNECT_TIME.md CURLINFO_CONNECT_TIME_T.md CURLINFO_CONN_ID.md CURLINFO_CONTENT_LENGTH_DOWNLOAD.md CURLINFO_CONTENT_LENGTH_DOWNLOAD_T.md CURLINFO_CONTENT_LENGTH_UPLOAD.md CURLINFO_CONTENT_LENGTH_UPLOAD_T.md CURLINFO_CONTENT_TYPE.md CURLINFO_COOKIELIST.md CURLINFO_EARLYDATA_SENT_T.md CURLINFO_EFFECTIVE_METHOD.md CURLINFO_EFFECTIVE_URL.md CURLINFO_FILETIME.md CURLINFO_FILETIME_T.md CURLINFO_FTP_ENTRY_PATH.md CURLINFO_HEADER_SIZE.md CURLINFO_HTTPAUTH_AVAIL.md CURLINFO_HTTPAUTH_USED.md CURLINFO_HTTP_CONNECTCODE.md CURLINFO_HTTP_VERSION.md CURLINFO_LASTSOCKET.md CURLINFO_LOCAL_IP.md CURLINFO_LOCAL_PORT.md CURLINFO_NAMELOOKUP_TIME.md CURLINFO_NAMELOOKUP_TIME_T.md CURLINFO_NUM_CONNECTS.md CURLINFO_OS_ERRNO.md CURLINFO_POSTTRANSFER_TIME_T.md CURLINFO_PRETRANSFER_TIME.md CURLINFO_PRETRANSFER_TIME_T.md CURLINFO_PRIMARY_IP.md CURLINFO_PRIMARY_PORT.md CURLINFO_PRIVATE.md CURLINFO_PROTOCOL.md CURLINFO_PROXYAUTH_AVAIL.md CURLINFO_PROXYAUTH_USED.md CURLINFO_PROXY_ERROR.md CURLINFO_PROXY_SSL_VERIFYRESULT.md CURLINFO_QUEUE_TIME_T.md CURLINFO_REDIRECT_COUNT.md CURLINFO_REDIRECT_TIME.md CURLINFO_REDIRECT_TIME_T.md CURLINFO_REDIRECT_URL.md CURLINFO_REFERER.md CURLINFO_REQUEST_SIZE.md CURLINFO_RESPONSE_CODE.md CURLINFO_RETRY_AFTER.md CURLINFO_RTSP_CLIENT_CSEQ.md CURLINFO_RTSP_CSEQ_RECV.md CURLINFO_RTSP_SERVER_CSEQ.md CURLINFO_RTSP_SESSION_ID.md CURLINFO_SCHEME.md CURLINFO_SIZE_DELIVERED.md CURLINFO_SIZE_DOWNLOAD.md CURLINFO_SIZE_DOWNLOAD_T.md CURLINFO_SIZE_UPLOAD.md CURLINFO_SIZE_UPLOAD_T.md CURLINFO_SPEED_DOWNLOAD.md CURLINFO_SPEED_DOWNLOAD_T.md CURLINFO_SPEED_UPLOAD.md CURLINFO_SPEED_UPLOAD_T.md CURLINFO_SSL_ENGINES.md CURLINFO_SSL_VERIFYRESULT.md CURLINFO_STARTTRANSFER_TIME.md CURLINFO_STARTTRANSFER_TIME_T.md CURLINFO_TLS_SESSION.md CURLINFO_TLS_SSL_PTR.md CURLINFO_TOTAL_TIME.md CURLINFO_TOTAL_TIME_T.md CURLINFO_USED_PROXY.md CURLINFO_XFER_ID.md CURLMINFO_XFERS_ADDED.md CURLMINFO_XFERS_CURRENT.md CURLMINFO_XFERS_DONE.md CURLMINFO_XFERS_PENDING.md CURLMINFO_XFERS_RUNNING.md CURLMOPT_CHUNK_LENGTH_PENALTY_SIZE.md CURLMOPT_CONTENT_LENGTH_PENALTY_SIZE.md CURLMOPT_MAXCONNECTS.md CURLMOPT_MAX_CONCURRENT_STREAMS.md CURLMOPT_MAX_HOST_CONNECTIONS.md CURLMOPT_MAX_PIPELINE_LENGTH.md CURLMOPT_MAX_TOTAL_CONNECTIONS.md CURLMOPT_NETWORK_CHANGED.md CURLMOPT_NOTIFYDATA.md CURLMOPT_NOTIFYFUNCTION.md CURLMOPT_PIPELINING.md CURLMOPT_PIPELINING_SERVER_BL.md CURLMOPT_PIPELINING_SITE_BL.md CURLMOPT_PUSHDATA.md CURLMOPT_PUSHFUNCTION.md CURLMOPT_QUICK_EXIT.md CURLMOPT_RESOLVE_THREADS_MAX.md CURLMOPT_SOCKETDATA.md CURLMOPT_SOCKETFUNCTION.md CURLMOPT_TIMERDATA.md CURLMOPT_TIMERFUNCTION.md CURLOPT_ABSTRACT_UNIX_SOCKET.md CURLOPT_ACCEPTTIMEOUT_MS.md CURLOPT_ACCEPT_ENCODING.md CURLOPT_ADDRESS_SCOPE.md CURLOPT_ALTSVC.md CURLOPT_ALTSVC_CTRL.md CURLOPT_APPEND.md CURLOPT_AUTOREFERER.md CURLOPT_AWS_SIGV4.md CURLOPT_BUFFERSIZE.md CURLOPT_CAINFO.md CURLOPT_CAINFO_BLOB.md CURLOPT_CAPATH.md CURLOPT_CA_CACHE_TIMEOUT.md CURLOPT_CERTINFO.md CURLOPT_CHUNK_BGN_FUNCTION.md CURLOPT_CHUNK_DATA.md CURLOPT_CHUNK_END_FUNCTION.md CURLOPT_CLOSESOCKETDATA.md CURLOPT_CLOSESOCKETFUNCTION.md CURLOPT_CONNECTTIMEOUT.md CURLOPT_CONNECTTIMEOUT_MS.md CURLOPT_CONNECT_ONLY.md CURLOPT_CONNECT_TO.md CURLOPT_CONV_FROM_NETWORK_FUNCTION.md CURLOPT_CONV_FROM_UTF8_FUNCTION.md CURLOPT_CONV_TO_NETWORK_FUNCTION.md CURLOPT_COOKIE.md CURLOPT_COOKIEFILE.md CURLOPT_COOKIEJAR.md CURLOPT_COOKIELIST.md CURLOPT_COOKIESESSION.md CURLOPT_COPYPOSTFIELDS.md CURLOPT_CRLF.md CURLOPT_CRLFILE.md CURLOPT_CURLU.md CURLOPT_CUSTOMREQUEST.md CURLOPT_DEBUGDATA.md CURLOPT_DEBUGFUNCTION.md CURLOPT_DEFAULT_PROTOCOL.md CURLOPT_DIRLISTONLY.md CURLOPT_DISALLOW_USERNAME_IN_URL.md CURLOPT_DNS_CACHE_TIMEOUT.md CURLOPT_DNS_INTERFACE.md CURLOPT_DNS_LOCAL_IP4.md CURLOPT_DNS_LOCAL_IP6.md CURLOPT_DNS_SERVERS.md CURLOPT_DNS_SHUFFLE_ADDRESSES.md CURLOPT_DNS_USE_GLOBAL_CACHE.md CURLOPT_DOH_SSL_VERIFYHOST.md CURLOPT_DOH_SSL_VERIFYPEER.md CURLOPT_DOH_SSL_VERIFYSTATUS.md CURLOPT_DOH_URL.md CURLOPT_ECH.md CURLOPT_EGDSOCKET.md CURLOPT_ERRORBUFFER.md CURLOPT_EXPECT_100_TIMEOUT_MS.md CURLOPT_FAILONERROR.md CURLOPT_FILETIME.md CURLOPT_FNMATCH_DATA.md CURLOPT_FNMATCH_FUNCTION.md CURLOPT_FOLLOWLOCATION.md CURLOPT_FORBID_REUSE.md CURLOPT_FRESH_CONNECT.md CURLOPT_FTPPORT.md CURLOPT_FTPSSLAUTH.md CURLOPT_FTP_ACCOUNT.md CURLOPT_FTP_ALTERNATIVE_TO_USER.md CURLOPT_FTP_CREATE_MISSING_DIRS.md CURLOPT_FTP_FILEMETHOD.md CURLOPT_FTP_SKIP_PASV_IP.md CURLOPT_FTP_SSL_CCC.md CURLOPT_FTP_USE_EPRT.md CURLOPT_FTP_USE_EPSV.md CURLOPT_FTP_USE_PRET.md CURLOPT_GSSAPI_DELEGATION.md CURLOPT_HAPPY_EYEBALLS_TIMEOUT_MS.md CURLOPT_HAPROXYPROTOCOL.md CURLOPT_HAPROXY_CLIENT_IP.md CURLOPT_HEADER.md CURLOPT_HEADERDATA.md CURLOPT_HEADERFUNCTION.md CURLOPT_HEADEROPT.md CURLOPT_HSTS.md CURLOPT_HSTSREADDATA.md CURLOPT_HSTSREADFUNCTION.md CURLOPT_HSTSWRITEDATA.md CURLOPT_HSTSWRITEFUNCTION.md CURLOPT_HSTS_CTRL.md CURLOPT_HTTP09_ALLOWED.md CURLOPT_HTTP200ALIASES.md CURLOPT_HTTPAUTH.md CURLOPT_HTTPGET.md CURLOPT_HTTPHEADER.md CURLOPT_HTTPPOST.md CURLOPT_HTTPPROXYTUNNEL.md CURLOPT_HTTP_CONTENT_DECODING.md CURLOPT_HTTP_TRANSFER_DECODING.md CURLOPT_HTTP_VERSION.md CURLOPT_IGNORE_CONTENT_LENGTH.md CURLOPT_INFILESIZE.md CURLOPT_INFILESIZE_LARGE.md CURLOPT_INTERFACE.md CURLOPT_INTERLEAVEDATA.md CURLOPT_INTERLEAVEFUNCTION.md CURLOPT_IOCTLDATA.md CURLOPT_IOCTLFUNCTION.md CURLOPT_IPRESOLVE.md CURLOPT_ISSUERCERT.md CURLOPT_ISSUERCERT_BLOB.md CURLOPT_KEEP_SENDING_ON_ERROR.md CURLOPT_KEYPASSWD.md CURLOPT_KRBLEVEL.md CURLOPT_LOCALPORT.md CURLOPT_LOCALPORTRANGE.md CURLOPT_LOGIN_OPTIONS.md CURLOPT_LOW_SPEED_LIMIT.md CURLOPT_LOW_SPEED_TIME.md CURLOPT_MAIL_AUTH.md CURLOPT_MAIL_FROM.md CURLOPT_MAIL_RCPT.md CURLOPT_MAIL_RCPT_ALLOWFAILS.md CURLOPT_MAXAGE_CONN.md CURLOPT_MAXCONNECTS.md CURLOPT_MAXFILESIZE.md CURLOPT_MAXFILESIZE_LARGE.md CURLOPT_MAXLIFETIME_CONN.md CURLOPT_MAXREDIRS.md CURLOPT_MAX_RECV_SPEED_LARGE.md CURLOPT_MAX_SEND_SPEED_LARGE.md CURLOPT_MIMEPOST.md CURLOPT_MIME_OPTIONS.md CURLOPT_NETRC.md CURLOPT_NETRC_FILE.md CURLOPT_NEW_DIRECTORY_PERMS.md CURLOPT_NEW_FILE_PERMS.md CURLOPT_NOBODY.md CURLOPT_NOPROGRESS.md CURLOPT_NOPROXY.md CURLOPT_NOSIGNAL.md CURLOPT_OPENSOCKETDATA.md CURLOPT_OPENSOCKETFUNCTION.md CURLOPT_PASSWORD.md CURLOPT_PATH_AS_IS.md CURLOPT_PINNEDPUBLICKEY.md CURLOPT_PIPEWAIT.md CURLOPT_PORT.md CURLOPT_POST.md CURLOPT_POSTFIELDS.md CURLOPT_POSTFIELDSIZE.md CURLOPT_POSTFIELDSIZE_LARGE.md CURLOPT_POSTQUOTE.md CURLOPT_POSTREDIR.md CURLOPT_PREQUOTE.md CURLOPT_PREREQDATA.md CURLOPT_PREREQFUNCTION.md CURLOPT_PRE_PROXY.md CURLOPT_PRIVATE.md CURLOPT_PROGRESSDATA.md CURLOPT_PROGRESSFUNCTION.md CURLOPT_PROTOCOLS.md CURLOPT_PROTOCOLS_STR.md CURLOPT_PROXY.md CURLOPT_PROXYAUTH.md CURLOPT_PROXYHEADER.md CURLOPT_PROXYPASSWORD.md CURLOPT_PROXYPORT.md CURLOPT_PROXYTYPE.md CURLOPT_PROXYUSERNAME.md CURLOPT_PROXYUSERPWD.md CURLOPT_PROXY_CAINFO.md CURLOPT_PROXY_CAINFO_BLOB.md CURLOPT_PROXY_CAPATH.md CURLOPT_PROXY_CRLFILE.md CURLOPT_PROXY_ISSUERCERT.md CURLOPT_PROXY_ISSUERCERT_BLOB.md CURLOPT_PROXY_KEYPASSWD.md CURLOPT_PROXY_PINNEDPUBLICKEY.md CURLOPT_PROXY_SERVICE_NAME.md CURLOPT_PROXY_SSLCERT.md CURLOPT_PROXY_SSLCERTTYPE.md CURLOPT_PROXY_SSLCERT_BLOB.md CURLOPT_PROXY_SSLKEY.md CURLOPT_PROXY_SSLKEYTYPE.md CURLOPT_PROXY_SSLKEY_BLOB.md CURLOPT_PROXY_SSLVERSION.md CURLOPT_PROXY_SSL_CIPHER_LIST.md CURLOPT_PROXY_SSL_OPTIONS.md CURLOPT_PROXY_SSL_VERIFYHOST.md CURLOPT_PROXY_SSL_VERIFYPEER.md CURLOPT_PROXY_TLS13_CIPHERS.md CURLOPT_PROXY_TLSAUTH_PASSWORD.md CURLOPT_PROXY_TLSAUTH_TYPE.md CURLOPT_PROXY_TLSAUTH_USERNAME.md CURLOPT_PROXY_TRANSFER_MODE.md CURLOPT_PUT.md CURLOPT_QUICK_EXIT.md CURLOPT_QUOTE.md CURLOPT_RANDOM_FILE.md CURLOPT_RANGE.md CURLOPT_READDATA.md CURLOPT_READFUNCTION.md CURLOPT_REDIR_PROTOCOLS.md CURLOPT_REDIR_PROTOCOLS_STR.md CURLOPT_REFERER.md CURLOPT_REQUEST_TARGET.md CURLOPT_RESOLVE.md CURLOPT_RESOLVER_START_DATA.md CURLOPT_RESOLVER_START_FUNCTION.md CURLOPT_RESUME_FROM.md CURLOPT_RESUME_FROM_LARGE.md CURLOPT_RTSP_CLIENT_CSEQ.md CURLOPT_RTSP_REQUEST.md CURLOPT_RTSP_SERVER_CSEQ.md CURLOPT_RTSP_SESSION_ID.md CURLOPT_RTSP_STREAM_URI.md CURLOPT_RTSP_TRANSPORT.md CURLOPT_SASL_AUTHZID.md CURLOPT_SASL_IR.md CURLOPT_SEEKDATA.md CURLOPT_SEEKFUNCTION.md CURLOPT_SERVER_RESPONSE_TIMEOUT.md CURLOPT_SERVER_RESPONSE_TIMEOUT_MS.md CURLOPT_SERVICE_NAME.md CURLOPT_SHARE.md CURLOPT_SOCKOPTDATA.md CURLOPT_SOCKOPTFUNCTION.md CURLOPT_SOCKS5_AUTH.md CURLOPT_SOCKS5_GSSAPI_NEC.md CURLOPT_SOCKS5_GSSAPI_SERVICE.md CURLOPT_SSH_AUTH_TYPES.md CURLOPT_SSH_COMPRESSION.md CURLOPT_SSH_HOSTKEYDATA.md CURLOPT_SSH_HOSTKEYFUNCTION.md CURLOPT_SSH_HOST_PUBLIC_KEY_MD5.md CURLOPT_SSH_HOST_PUBLIC_KEY_SHA256.md CURLOPT_SSH_KEYDATA.md CURLOPT_SSH_KEYFUNCTION.md CURLOPT_SSH_KNOWNHOSTS.md CURLOPT_SSH_PRIVATE_KEYFILE.md CURLOPT_SSH_PUBLIC_KEYFILE.md CURLOPT_SSLCERT.md CURLOPT_SSLCERTTYPE.md CURLOPT_SSLCERT_BLOB.md CURLOPT_SSLENGINE.md CURLOPT_SSLENGINE_DEFAULT.md CURLOPT_SSLKEY.md CURLOPT_SSLKEYTYPE.md CURLOPT_SSLKEY_BLOB.md CURLOPT_SSLVERSION.md CURLOPT_SSL_CIPHER_LIST.md CURLOPT_SSL_CTX_DATA.md CURLOPT_SSL_CTX_FUNCTION.md CURLOPT_SSL_EC_CURVES.md CURLOPT_SSL_ENABLE_ALPN.md CURLOPT_SSL_ENABLE_NPN.md CURLOPT_SSL_FALSESTART.md CURLOPT_SSL_OPTIONS.md CURLOPT_SSL_SESSIONID_CACHE.md CURLOPT_SSL_SIGNATURE_ALGORITHMS.md CURLOPT_SSL_VERIFYHOST.md CURLOPT_SSL_VERIFYPEER.md CURLOPT_SSL_VERIFYSTATUS.md CURLOPT_STDERR.md CURLOPT_STREAM_DEPENDS.md CURLOPT_STREAM_DEPENDS_E.md CURLOPT_STREAM_WEIGHT.md CURLOPT_SUPPRESS_CONNECT_HEADERS.md CURLOPT_TCP_FASTOPEN.md CURLOPT_TCP_KEEPALIVE.md CURLOPT_TCP_KEEPCNT.md CURLOPT_TCP_KEEPIDLE.md CURLOPT_TCP_KEEPINTVL.md CURLOPT_TCP_NODELAY.md CURLOPT_TELNETOPTIONS.md CURLOPT_TFTP_BLKSIZE.md CURLOPT_TFTP_NO_OPTIONS.md CURLOPT_TIMECONDITION.md CURLOPT_TIMEOUT.md CURLOPT_TIMEOUT_MS.md CURLOPT_TIMEVALUE.md CURLOPT_TIMEVALUE_LARGE.md CURLOPT_TLS13_CIPHERS.md CURLOPT_TLSAUTH_PASSWORD.md CURLOPT_TLSAUTH_TYPE.md CURLOPT_TLSAUTH_USERNAME.md CURLOPT_TRAILERDATA.md CURLOPT_TRAILERFUNCTION.md CURLOPT_TRANSFERTEXT.md CURLOPT_TRANSFER_ENCODING.md CURLOPT_UNIX_SOCKET_PATH.md CURLOPT_UNRESTRICTED_AUTH.md CURLOPT_UPKEEP_INTERVAL_MS.md CURLOPT_UPLOAD.md CURLOPT_UPLOAD_BUFFERSIZE.md CURLOPT_UPLOAD_FLAGS.md CURLOPT_URL.md CURLOPT_USERAGENT.md CURLOPT_USERNAME.md CURLOPT_USERPWD.md CURLOPT_USE_SSL.md CURLOPT_VERBOSE.md CURLOPT_WILDCARDMATCH.md CURLOPT_WRITEDATA.md CURLOPT_WRITEFUNCTION.md CURLOPT_WS_OPTIONS.md CURLOPT_XFERINFODATA.md CURLOPT_XFERINFOFUNCTION.md CURLOPT_XOAUTH2_BEARER.md CURLSHOPT_LOCKFUNC.md CURLSHOPT_SHARE.md CURLSHOPT_UNLOCKFUNC.md CURLSHOPT_UNSHARE.md CURLSHOPT_USERDATA.md Makefile.am Makefile.incinclude
curl
Makefile.am curl.h curlver.h easy.h header.h mprintf.h multi.h options.h stdcheaders.h system.h typecheck-gcc.h urlapi.h websockets.hlib
curlx
base64.c base64.h basename.c basename.h dynbuf.c dynbuf.h fopen.c fopen.h inet_ntop.c inet_ntop.h inet_pton.c inet_pton.h multibyte.c multibyte.h nonblock.c nonblock.h snprintf.c snprintf.h strcopy.c strcopy.h strdup.c strdup.h strerr.c strerr.h strparse.c strparse.h timediff.c timediff.h timeval.c timeval.h version_win32.c version_win32.h wait.c wait.h warnless.c warnless.h winapi.c winapi.hvauth
cleartext.c cram.c digest.c digest.h digest_sspi.c gsasl.c krb5_gssapi.c krb5_sspi.c ntlm.c ntlm_sspi.c oauth2.c spnego_gssapi.c spnego_sspi.c vauth.c vauth.hvquic
curl_ngtcp2.c curl_ngtcp2.h curl_quiche.c curl_quiche.h vquic-tls.c vquic-tls.h vquic.c vquic.h vquic_int.hvtls
apple.c apple.h cipher_suite.c cipher_suite.h gtls.c gtls.h hostcheck.c hostcheck.h keylog.c keylog.h mbedtls.c mbedtls.h openssl.c openssl.h rustls.c rustls.h schannel.c schannel.h schannel_int.h schannel_verify.c vtls.c vtls.h vtls_int.h vtls_scache.c vtls_scache.h vtls_spack.c vtls_spack.h wolfssl.c wolfssl.h x509asn1.c x509asn1.hm4
.gitignore curl-amissl.m4 curl-apple-sectrust.m4 curl-compilers.m4 curl-confopts.m4 curl-functions.m4 curl-gnutls.m4 curl-mbedtls.m4 curl-openssl.m4 curl-override.m4 curl-reentrant.m4 curl-rustls.m4 curl-schannel.m4 curl-sysconfig.m4 curl-wolfssl.m4 xc-am-iface.m4 xc-cc-check.m4 xc-lt-iface.m4 xc-val-flgs.m4 zz40-xc-ovr.m4 zz50-xc-ovr.m4projects
OS400
.checksrc README.OS400 ccsidcurl.c ccsidcurl.h config400.default curl.cmd curl.inc.in curlcl.c curlmain.c initscript.sh make-docs.sh make-include.sh make-lib.sh make-src.sh make-tests.sh makefile.sh os400sys.c os400sys.hWindows
tmpl
.gitattributes README.txt curl-all.sln curl.sln curl.vcxproj curl.vcxproj.filters libcurl.sln libcurl.vcxproj libcurl.vcxproj.filtersvms
Makefile.am backup_gnv_curl_src.com build_curl-config_script.com build_gnv_curl.com build_gnv_curl_pcsi_desc.com build_gnv_curl_pcsi_text.com build_gnv_curl_release_notes.com build_libcurl_pc.com build_vms.com clean_gnv_curl.com compare_curl_source.com config_h.com curl_crtl_init.c curl_gnv_build_steps.txt curl_release_note_start.txt curl_startup.com curlmsg.h curlmsg.msg curlmsg.sdl curlmsg_vms.h generate_config_vms_h_curl.com generate_vax_transfer.com gnv_conftest.c_first gnv_curl_configure.sh gnv_libcurl_symbols.opt gnv_link_curl.com macro32_exactcase.patch make_gnv_curl_install.sh make_pcsi_curl_kit_name.com pcsi_gnv_curl_file_list.txt pcsi_product_gnv_curl.com readme report_openssl_version.c setup_gnv_curl_build.com stage_curl_install.com vms_eco_level.hscripts
.checksrc CMakeLists.txt Makefile.am badwords badwords-all badwords.txt cd2cd cd2nroff cdall checksrc-all.pl checksrc.pl cmakelint.sh completion.pl contributors.sh contrithanks.sh coverage.sh delta dmaketgz extract-unit-protos firefox-db2pem.sh installcheck.sh maketgz managen mdlinkcheck mk-ca-bundle.pl mk-unity.pl nroff2cd perlcheck.sh pythonlint.sh randdisable release-notes.pl release-tools.sh schemetable.c singleuse.pl spacecheck.pl top-complexity top-length verify-release wcurlsrc
.checksrc .gitignore CMakeLists.txt Makefile.am Makefile.inc config2setopts.c config2setopts.h curl.rc curlinfo.c mk-file-embed.pl mkhelp.pl slist_wc.c slist_wc.h terminal.c terminal.h tool_cb_dbg.c tool_cb_dbg.h tool_cb_hdr.c tool_cb_hdr.h tool_cb_prg.c tool_cb_prg.h tool_cb_rea.c tool_cb_rea.h tool_cb_see.c tool_cb_see.h tool_cb_soc.c tool_cb_soc.h tool_cb_wrt.c tool_cb_wrt.h tool_cfgable.c tool_cfgable.h tool_dirhie.c tool_dirhie.h tool_doswin.c tool_doswin.h tool_easysrc.c tool_easysrc.h tool_filetime.c tool_filetime.h tool_findfile.c tool_findfile.h tool_formparse.c tool_formparse.h tool_getparam.c tool_getparam.h tool_getpass.c tool_getpass.h tool_help.c tool_help.h tool_helpers.c tool_helpers.h tool_hugehelp.h tool_ipfs.c tool_ipfs.h tool_libinfo.c tool_libinfo.h tool_listhelp.c tool_main.c tool_main.h tool_msgs.c tool_msgs.h tool_operate.c tool_operate.h tool_operhlp.c tool_operhlp.h tool_paramhlp.c tool_paramhlp.h tool_parsecfg.c tool_parsecfg.h tool_progress.c tool_progress.h tool_sdecls.h tool_setopt.c tool_setopt.h tool_setup.h tool_ssls.c tool_ssls.h tool_stderr.c tool_stderr.h tool_urlglob.c tool_urlglob.h tool_util.c tool_util.h tool_version.h tool_vms.c tool_vms.h tool_writeout.c tool_writeout.h tool_writeout_json.c tool_writeout_json.h tool_xattr.c tool_xattr.h var.c var.htests
certs
.gitignore CMakeLists.txt Makefile.am Makefile.inc genserv.pl srp-verifier-conf srp-verifier-db test-ca.cnf test-ca.prm test-client-cert.prm test-client-eku-only.prm test-localhost-san-first.prm test-localhost-san-last.prm test-localhost.nn.prm test-localhost.prm test-localhost0h.prmdata
.gitignore DISABLED Makefile.am data-xml1 data1400.c data1401.c data1402.c data1403.c data1404.c data1405.c data1406.c data1407.c data1420.c data1461.txt data1463.txt data1465.c data1481.c data1705-1.md data1705-2.md data1705-3.md data1705-4.md data1705-stdout.1 data1706-1.md data1706-2.md data1706-3.md data1706-4.md data1706-stdout.txt data320.html test1 test10 test100 test1000 test1001 test1002 test1003 test1004 test1005 test1006 test1007 test1008 test1009 test101 test1010 test1011 test1012 test1013 test1014 test1015 test1016 test1017 test1018 test1019 test102 test1020 test1021 test1022 test1023 test1024 test1025 test1026 test1027 test1028 test1029 test103 test1030 test1031 test1032 test1033 test1034 test1035 test1036 test1037 test1038 test1039 test104 test1040 test1041 test1042 test1043 test1044 test1045 test1046 test1047 test1048 test1049 test105 test1050 test1051 test1052 test1053 test1054 test1055 test1056 test1057 test1058 test1059 test106 test1060 test1061 test1062 test1063 test1064 test1065 test1066 test1067 test1068 test1069 test107 test1070 test1071 test1072 test1073 test1074 test1075 test1076 test1077 test1078 test1079 test108 test1080 test1081 test1082 test1083 test1084 test1085 test1086 test1087 test1088 test1089 test109 test1090 test1091 test1092 test1093 test1094 test1095 test1096 test1097 test1098 test1099 test11 test110 test1100 test1101 test1102 test1103 test1104 test1105 test1106 test1107 test1108 test1109 test111 test1110 test1111 test1112 test1113 test1114 test1115 test1116 test1117 test1118 test1119 test112 test1120 test1121 test1122 test1123 test1124 test1125 test1126 test1127 test1128 test1129 test113 test1130 test1131 test1132 test1133 test1134 test1135 test1136 test1137 test1138 test1139 test114 test1140 test1141 test1142 test1143 test1144 test1145 test1146 test1147 test1148 test1149 test115 test1150 test1151 test1152 test1153 test1154 test1155 test1156 test1157 test1158 test1159 test116 test1160 test1161 test1162 test1163 test1164 test1165 test1166 test1167 test1168 test1169 test117 test1170 test1171 test1172 test1173 test1174 test1175 test1176 test1177 test1178 test1179 test118 test1180 test1181 test1182 test1183 test1184 test1185 test1186 test1187 test1188 test1189 test119 test1190 test1191 test1192 test1193 test1194 test1195 test1196 test1197 test1198 test1199 test12 test120 test1200 test1201 test1202 test1203 test1204 test1205 test1206 test1207 test1208 test1209 test121 test1210 test1211 test1212 test1213 test1214 test1215 test1216 test1217 test1218 test1219 test122 test1220 test1221 test1222 test1223 test1224 test1225 test1226 test1227 test1228 test1229 test123 test1230 test1231 test1232 test1233 test1234 test1235 test1236 test1237 test1238 test1239 test124 test1240 test1241 test1242 test1243 test1244 test1245 test1246 test1247 test1248 test1249 test125 test1250 test1251 test1252 test1253 test1254 test1255 test1256 test1257 test1258 test1259 test126 test1260 test1261 test1262 test1263 test1264 test1265 test1266 test1267 test1268 test1269 test127 test1270 test1271 test1272 test1273 test1274 test1275 test1276 test1277 test1278 test1279 test128 test1280 test1281 test1282 test1283 test1284 test1285 test1286 test1287 test1288 test1289 test129 test1290 test1291 test1292 test1293 test1294 test1295 test1296 test1297 test1298 test1299 test13 test130 test1300 test1301 test1302 test1303 test1304 test1305 test1306 test1307 test1308 test1309 test131 test1310 test1311 test1312 test1313 test1314 test1315 test1316 test1317 test1318 test1319 test132 test1320 test1321 test1322 test1323 test1324 test1325 test1326 test1327 test1328 test1329 test133 test1330 test1331 test1332 test1333 test1334 test1335 test1336 test1337 test1338 test1339 test134 test1340 test1341 test1342 test1343 test1344 test1345 test1346 test1347 test1348 test1349 test135 test1350 test1351 test1352 test1353 test1354 test1355 test1356 test1357 test1358 test1359 test136 test1360 test1361 test1362 test1363 test1364 test1365 test1366 test1367 test1368 test1369 test137 test1370 test1371 test1372 test1373 test1374 test1375 test1376 test1377 test1378 test1379 test138 test1380 test1381 test1382 test1383 test1384 test1385 test1386 test1387 test1388 test1389 test139 test1390 test1391 test1392 test1393 test1394 test1395 test1396 test1397 test1398 test1399 test14 test140 test1400 test1401 test1402 test1403 test1404 test1405 test1406 test1407 test1408 test1409 test141 test1410 test1411 test1412 test1413 test1414 test1415 test1416 test1417 test1418 test1419 test142 test1420 test1421 test1422 test1423 test1424 test1425 test1426 test1427 test1428 test1429 test143 test1430 test1431 test1432 test1433 test1434 test1435 test1436 test1437 test1438 test1439 test144 test1440 test1441 test1442 test1443 test1444 test1445 test1446 test1447 test1448 test1449 test145 test1450 test1451 test1452 test1453 test1454 test1455 test1456 test1457 test1458 test1459 test146 test1460 test1461 test1462 test1463 test1464 test1465 test1466 test1467 test1468 test1469 test147 test1470 test1471 test1472 test1473 test1474 test1475 test1476 test1477 test1478 test1479 test148 test1480 test1481 test1482 test1483 test1484 test1485 test1486 test1487 test1488 test1489 test149 test1490 test1491 test1492 test1493 test1494 test1495 test1496 test1497 test1498 test1499 test15 test150 test1500 test1501 test1502 test1503 test1504 test1505 test1506 test1507 test1508 test1509 test151 test1510 test1511 test1512 test1513 test1514 test1515 test1516 test1517 test1518 test1519 test152 test1520 test1521 test1522 test1523 test1524 test1525 test1526 test1527 test1528 test1529 test153 test1530 test1531 test1532 test1533 test1534 test1535 test1536 test1537 test1538 test1539 test154 test1540 test1541 test1542 test1543 test1544 test1545 test1546 test1547 test1548 test1549 test155 test1550 test1551 test1552 test1553 test1554 test1555 test1556 test1557 test1558 test1559 test156 test1560 test1561 test1562 test1563 test1564 test1565 test1566 test1567 test1568 test1569 test157 test1570 test1571 test1572 test1573 test1574 test1575 test1576 test1577 test1578 test1579 test158 test1580 test1581 test1582 test1583 test1584 test1585 test1586 test1587 test1588 test1589 test159 test1590 test1591 test1592 test1593 test1594 test1595 test1596 test1597 test1598 test1599 test16 test160 test1600 test1601 test1602 test1603 test1604 test1605 test1606 test1607 test1608 test1609 test161 test1610 test1611 test1612 test1613 test1614 test1615 test1616 test1617 test1618 test1619 test162 test1620 test1621 test1622 test1623 test1624 test1625 test1626 test1627 test1628 test1629 test163 test1630 test1631 test1632 test1633 test1634 test1635 test1636 test1637 test1638 test1639 test164 test1640 test1641 test1642 test1643 test1644 test1645 test165 test1650 test1651 test1652 test1653 test1654 test1655 test1656 test1657 test1658 test1659 test166 test1660 test1661 test1662 test1663 test1664 test1665 test1666 test1667 test1668 test1669 test167 test1670 test1671 test1672 test1673 test1674 test1675 test1676 test168 test1680 test1681 test1682 test1683 test1684 test1685 test169 test17 test170 test1700 test1701 test1702 test1703 test1704 test1705 test1706 test1707 test1708 test1709 test171 test1710 test1711 test1712 test1713 test1714 test1715 test172 test1720 test1721 test173 test174 test175 test176 test177 test178 test179 test18 test180 test1800 test1801 test1802 test181 test182 test183 test184 test1847 test1848 test1849 test185 test1850 test1851 test186 test187 test188 test189 test19 test190 test1900 test1901 test1902 test1903 test1904 test1905 test1906 test1907 test1908 test1909 test191 test1910 test1911 test1912 test1913 test1914 test1915 test1916 test1917 test1918 test1919 test192 test1920 test1921 test193 test1933 test1934 test1935 test1936 test1937 test1938 test1939 test194 test1940 test1941 test1942 test1943 test1944 test1945 test1946 test1947 test1948 test195 test1955 test1956 test1957 test1958 test1959 test196 test1960 test1964 test1965 test1966 test197 test1970 test1971 test1972 test1973 test1974 test1975 test1976 test1977 test1978 test1979 test198 test1980 test1981 test1982 test1983 test1984 test199 test2 test20 test200 test2000 test2001 test2002 test2003 test2004 test2005 test2006 test2007 test2008 test2009 test201 test2010 test2011 test2012 test2013 test2014 test202 test2023 test2024 test2025 test2026 test2027 test2028 test2029 test203 test2030 test2031 test2032 test2033 test2034 test2035 test2037 test2038 test2039 test204 test2040 test2041 test2042 test2043 test2044 test2045 test2046 test2047 test2048 test2049 test205 test2050 test2051 test2052 test2053 test2054 test2055 test2056 test2057 test2058 test2059 test206 test2060 test2061 test2062 test2063 test2064 test2065 test2066 test2067 test2068 test2069 test207 test2070 test2071 test2072 test2073 test2074 test2075 test2076 test2077 test2078 test2079 test208 test2080 test2081 test2082 test2083 test2084 test2085 test2086 test2087 test2088 test2089 test209 test2090 test2091 test2092 test21 test210 test2100 test2101 test2102 test2103 test2104 test211 test212 test213 test214 test215 test216 test217 test218 test219 test22 test220 test2200 test2201 test2202 test2203 test2204 test2205 test2206 test2207 test221 test222 test223 test224 test225 test226 test227 test228 test229 test23 test230 test2300 test2301 test2302 test2303 test2304 test2306 test2307 test2308 test2309 test231 test232 test233 test234 test235 test236 test237 test238 test239 test24 test240 test2400 test2401 test2402 test2403 test2404 test2405 test2406 test2407 test2408 test2409 test241 test2410 test2411 test242 test243 test244 test245 test246 test247 test248 test249 test25 test250 test2500 test2501 test2502 test2503 test2504 test2505 test2506 test251 test252 test253 test254 test255 test256 test257 test258 test259 test26 test260 test2600 test2601 test2602 test2603 test2604 test2605 test261 test262 test263 test264 test265 test266 test267 test268 test269 test27 test270 test2700 test2701 test2702 test2703 test2704 test2705 test2706 test2707 test2708 test2709 test271 test2710 test2711 test2712 test2713 test2714 test2715 test2716 test2717 test2718 test2719 test272 test2720 test2721 test2722 test2723 test273 test274 test275 test276 test277 test278 test279 test28 test280 test281 test282 test283 test284 test285 test286 test287 test288 test289 test29 test290 test291 test292 test293 test294 test295 test296 test297 test298 test299 test3 test30 test300 test3000 test3001 test3002 test3003 test3004 test3005 test3006 test3007 test3008 test3009 test301 test3010 test3011 test3012 test3013 test3014 test3015 test3016 test3017 test3018 test3019 test302 test3020 test3021 test3022 test3023 test3024 test3025 test3026 test3027 test3028 test3029 test303 test3030 test3031 test3032 test3033 test3034 test3035 test3036 test304 test305 test306 test307 test308 test309 test31 test310 test3100 test3101 test3102 test3103 test3104 test3105 test3106 test311 test312 test313 test314 test315 test316 test317 test318 test319 test32 test320 test3200 test3201 test3202 test3203 test3204 test3205 test3206 test3207 test3208 test3209 test321 test3210 test3211 test3212 test3213 test3214 test3215 test3216 test3217 test3218 test3219 test322 test3220 test323 test324 test325 test326 test327 test328 test329 test33 test330 test3300 test3301 test3302 test331 test332 test333 test334 test335 test336 test337 test338 test339 test34 test340 test341 test342 test343 test344 test345 test346 test347 test348 test349 test35 test350 test351 test352 test353 test354 test355 test356 test357 test358 test359 test36 test360 test361 test362 test363 test364 test365 test366 test367 test368 test369 test37 test370 test371 test372 test373 test374 test375 test376 test378 test379 test38 test380 test381 test383 test384 test385 test386 test387 test388 test389 test39 test390 test391 test392 test393 test394 test395 test396 test397 test398 test399 test4 test40 test400 test4000 test4001 test401 test402 test403 test404 test405 test406 test407 test408 test409 test41 test410 test411 test412 test413 test414 test415 test416 test417 test418 test419 test42 test420 test421 test422 test423 test424 test425 test426 test427 test428 test429 test43 test430 test431 test432 test433 test434 test435 test436 test437 test438 test439 test44 test440 test441 test442 test443 test444 test445 test446 test447 test448 test449 test45 test450 test451 test452 test453 test454 test455 test456 test457 test458 test459 test46 test460 test461 test462 test463 test467 test468 test469 test47 test470 test471 test472 test473 test474 test475 test476 test477 test478 test479 test48 test480 test481 test482 test483 test484 test485 test486 test487 test488 test489 test49 test490 test491 test492 test493 test494 test495 test496 test497 test498 test499 test5 test50 test500 test501 test502 test503 test504 test505 test506 test507 test508 test509 test51 test510 test511 test512 test513 test514 test515 test516 test517 test518 test519 test52 test520 test521 test522 test523 test524 test525 test526 test527 test528 test529 test53 test530 test531 test532 test533 test534 test535 test536 test537 test538 test539 test54 test540 test541 test542 test543 test544 test545 test546 test547 test548 test549 test55 test550 test551 test552 test553 test554 test555 test556 test557 test558 test559 test56 test560 test561 test562 test563 test564 test565 test566 test567 test568 test569 test57 test570 test571 test572 test573 test574 test575 test576 test577 test578 test579 test58 test580 test581 test582 test583 test584 test585 test586 test587 test588 test589 test59 test590 test591 test592 test593 test594 test595 test596 test597 test598 test599 test6 test60 test600 test601 test602 test603 test604 test605 test606 test607 test608 test609 test61 test610 test611 test612 test613 test614 test615 test616 test617 test618 test619 test62 test620 test621 test622 test623 test624 test625 test626 test627 test628 test629 test63 test630 test631 test632 test633 test634 test635 test636 test637 test638 test639 test64 test640 test641 test642 test643 test644 test645 test646 test647 test648 test649 test65 test650 test651 test652 test653 test654 test655 test656 test658 test659 test66 test660 test661 test662 test663 test664 test665 test666 test667 test668 test669 test67 test670 test671 test672 test673 test674 test675 test676 test677 test678 test679 test68 test680 test681 test682 test683 test684 test685 test686 test687 test688 test689 test69 test690 test691 test692 test693 test694 test695 test696 test697 test698 test699 test7 test70 test700 test701 test702 test703 test704 test705 test706 test707 test708 test709 test71 test710 test711 test712 test713 test714 test715 test716 test717 test718 test719 test72 test720 test721 test722 test723 test724 test725 test726 test727 test728 test729 test73 test730 test731 test732 test733 test734 test735 test736 test737 test738 test739 test74 test740 test741 test742 test743 test744 test745 test746 test747 test748 test749 test75 test750 test751 test752 test753 test754 test755 test756 test757 test758 test759 test76 test760 test761 test762 test763 test764 test765 test766 test767 test768 test769 test77 test770 test771 test772 test773 test774 test775 test776 test777 test778 test779 test78 test780 test781 test782 test783 test784 test785 test786 test787 test788 test789 test79 test790 test791 test792 test793 test794 test795 test796 test797 test798 test799 test8 test80 test800 test801 test802 test803 test804 test805 test806 test807 test808 test809 test81 test810 test811 test812 test813 test814 test815 test816 test817 test818 test819 test82 test820 test821 test822 test823 test824 test825 test826 test827 test828 test829 test83 test830 test831 test832 test833 test834 test835 test836 test837 test838 test839 test84 test840 test841 test842 test843 test844 test845 test846 test847 test848 test849 test85 test850 test851 test852 test853 test854 test855 test856 test857 test858 test859 test86 test860 test861 test862 test863 test864 test865 test866 test867 test868 test869 test87 test870 test871 test872 test873 test874 test875 test876 test877 test878 test879 test88 test880 test881 test882 test883 test884 test885 test886 test887 test888 test889 test89 test890 test891 test892 test893 test894 test895 test896 test897 test898 test899 test9 test90 test900 test901 test902 test903 test904 test905 test906 test907 test908 test909 test91 test910 test911 test912 test913 test914 test915 test916 test917 test918 test919 test92 test920 test921 test922 test923 test924 test925 test926 test927 test928 test929 test93 test930 test931 test932 test933 test934 test935 test936 test937 test938 test939 test94 test940 test941 test942 test943 test944 test945 test946 test947 test948 test949 test95 test950 test951 test952 test953 test954 test955 test956 test957 test958 test959 test96 test960 test961 test962 test963 test964 test965 test966 test967 test968 test969 test97 test970 test971 test972 test973 test974 test975 test976 test977 test978 test979 test98 test980 test981 test982 test983 test984 test985 test986 test987 test988 test989 test99 test990 test991 test992 test993 test994 test995 test996 test997 test998 test999http
testenv
__init__.py caddy.py certs.py client.py curl.py dante.py dnsd.py env.py httpd.py nghttpx.py ports.py sshd.py vsftpd.py ws_echo_server.pylibtest
.gitignore CMakeLists.txt Makefile.am Makefile.inc cli_ftp_upload.c cli_h2_pausing.c cli_h2_serverpush.c cli_h2_upgrade_extreme.c cli_hx_download.c cli_hx_upload.c cli_tls_session_reuse.c cli_upload_pausing.c cli_ws_data.c cli_ws_pingpong.c first.c first.h lib1156.c lib1301.c lib1308.c lib1485.c lib1500.c lib1501.c lib1502.c lib1506.c lib1507.c lib1508.c lib1509.c lib1510.c lib1511.c lib1512.c lib1513.c lib1514.c lib1515.c lib1517.c lib1518.c lib1520.c lib1522.c lib1523.c lib1525.c lib1526.c lib1527.c lib1528.c lib1529.c lib1530.c lib1531.c lib1532.c lib1533.c lib1534.c lib1535.c lib1536.c lib1537.c lib1538.c lib1540.c lib1541.c lib1542.c lib1545.c lib1549.c lib1550.c lib1551.c lib1552.c lib1553.c lib1554.c lib1555.c lib1556.c lib1557.c lib1558.c lib1559.c lib1560.c lib1564.c lib1565.c lib1567.c lib1568.c lib1569.c lib1571.c lib1576.c lib1582.c lib1587.c lib1588.c lib1589.c lib1591.c lib1592.c lib1593.c lib1594.c lib1597.c lib1598.c lib1599.c lib1662.c lib1900.c lib1901.c lib1902.c lib1903.c lib1905.c lib1906.c lib1907.c lib1908.c lib1910.c lib1911.c lib1912.c lib1913.c lib1915.c lib1916.c lib1918.c lib1919.c lib1920.c lib1921.c lib1933.c lib1934.c lib1935.c lib1936.c lib1937.c lib1938.c lib1939.c lib1940.c lib1945.c lib1947.c lib1948.c lib1955.c lib1956.c lib1957.c lib1958.c lib1959.c lib1960.c lib1964.c lib1965.c lib1970.c lib1971.c lib1972.c lib1973.c lib1974.c lib1975.c lib1977.c lib1978.c lib2023.c lib2032.c lib2082.c lib2301.c lib2302.c lib2304.c lib2306.c lib2308.c lib2309.c lib2402.c lib2404.c lib2405.c lib2502.c lib2504.c lib2505.c lib2506.c lib2700.c lib3010.c lib3025.c lib3026.c lib3027.c lib3033.c lib3034.c lib3100.c lib3101.c lib3102.c lib3103.c lib3104.c lib3105.c lib3207.c lib3208.c lib500.c lib501.c lib502.c lib503.c lib504.c lib505.c lib506.c lib507.c lib508.c lib509.c lib510.c lib511.c lib512.c lib513.c lib514.c lib515.c lib516.c lib517.c lib518.c lib519.c lib520.c lib521.c lib523.c lib524.c lib525.c lib526.c lib530.c lib533.c lib536.c lib537.c lib539.c lib540.c lib541.c lib542.c lib543.c lib544.c lib547.c lib549.c lib552.c lib553.c lib554.c lib555.c lib556.c lib557.c lib558.c lib559.c lib560.c lib562.c lib564.c lib566.c lib567.c lib568.c lib569.c lib570.c lib571.c lib572.c lib573.c lib574.c lib575.c lib576.c lib578.c lib579.c lib582.c lib583.c lib586.c lib589.c lib590.c lib591.c lib597.c lib598.c lib599.c lib643.c lib650.c lib651.c lib652.c lib653.c lib654.c lib655.c lib658.c lib659.c lib661.c lib666.c lib667.c lib668.c lib670.c lib674.c lib676.c lib677.c lib678.c lib694.c lib695.c lib751.c lib753.c lib757.c lib758.c lib766.c memptr.c mk-lib1521.pl test1013.pl test1022.pl test307.pl test610.pl test613.pl testtrace.c testtrace.h testutil.c testutil.h unitcheck.hserver
.checksrc .gitignore CMakeLists.txt Makefile.am Makefile.inc dnsd.c first.c first.h getpart.c mqttd.c resolve.c rtspd.c sockfilt.c socksd.c sws.c tftpd.c util.ctunit
.gitignore CMakeLists.txt Makefile.am Makefile.inc README.md tool1394.c tool1604.c tool1621.c tool1622.c tool1623.c tool1720.cunit
.gitignore CMakeLists.txt Makefile.am Makefile.inc README.md unit1300.c unit1302.c unit1303.c unit1304.c unit1305.c unit1307.c unit1309.c unit1323.c unit1330.c unit1395.c unit1396.c unit1397.c unit1398.c unit1399.c unit1600.c unit1601.c unit1602.c unit1603.c unit1605.c unit1606.c unit1607.c unit1608.c unit1609.c unit1610.c unit1611.c unit1612.c unit1614.c unit1615.c unit1616.c unit1620.c unit1625.c unit1626.c unit1627.c unit1636.c unit1650.c unit1651.c unit1652.c unit1653.c unit1654.c unit1655.c unit1656.c unit1657.c unit1658.c unit1660.c unit1661.c unit1663.c unit1664.c unit1666.c unit1667.c unit1668.c unit1669.c unit1674.c unit1675.c unit1676.c unit1979.c unit1980.c unit2600.c unit2601.c unit2602.c unit2603.c unit2604.c unit2605.c unit3200.c unit3205.c unit3211.c unit3212.c unit3213.c unit3214.c unit3216.c unit3219.c unit3300.c unit3301.c unit3302.cexamples
.env config.ini crypto_test.lua env_test.lua fs_example.lua http_server.lua https_test.lua ini_example.lua json.lua log.lua path_fs_example.lua process_example.lua request_download.lua request_test.lua run_all.lua sqlite_example.lua sqlite_http_template.lua stash_test.lua template_test.lua timer.lua websocket.luainiparser
example
iniexample.c iniwrite.c parse.c twisted-errors.ini twisted-genhuge.py twisted-ofkey.ini twisted-ofval.ini twisted.initest
CMakeLists.txt test_dictionary.c test_iniparser.c unity-config.yml unity_config.hjinjac
libjinjac
src
CMakeLists.txt ast.c ast.h block_statement.c block_statement.h buffer.c buffer.h buildin.c buildin.h common.h convert.c convert.h flex_decl.h jfunction.c jfunction.h jinja_expression.l jinja_expression.y jinjac_parse.c jinjac_parse.h jinjac_stream.c jinjac_stream.h jlist.c jlist.h jobject.c jobject.h parameter.c parameter.h str_obj.c str_obj.h trace.c trace.htest
.gitignore CMakeLists.txt autotest.rb test_01.expected test_01.jinja test_01b.expected test_01b.jinja test_01c.expected test_01c.jinja test_01d.expected test_01d.jinja test_02.expected test_02.jinja test_03.expected test_03.jinja test_04.expected test_04.jinja test_05.expected test_05.jinja test_06.expected test_06.jinja test_07.expected test_07.jinja test_08.expected test_08.jinja test_08b.expected test_08b.jinja test_09.expected test_09.jinja test_10.expected test_10.jinja test_11.expected test_11.jinja test_12.expected test_12.jinja test_13.expected test_13.jinja test_14.expected test_14.jinja test_15.expected test_15.jinja test_16.expected test_16.jinja test_17.expected test_17.jinja test_18.expected test_18.jinja test_18b.expected test_18b.jinja test_18c.expected test_18c.jinja test_19.expected test_19.jinja test_19b.expected test_19b.jinja test_19c.expected test_19c.jinja test_19d.expected test_19d.jinja test_19e.expected test_19e.jinja test_19f.expected test_19f.jinja test_20.expected test_20.jinja test_21.expected test_21.jinja test_22.expected test_22.jinja test_22a.expected test_22a.jinja test_22b.expected test_22b.jinja test_23.expected test_23.jinja test_24.expected test_24.jinjalibev
Changes LICENSE Makefile Makefile.am Makefile.in README Symbols.ev Symbols.event aclocal.m4 autogen.sh compile config.guess config.h config.h.in config.status config.sub configure configure.ac depcomp ev++.h ev.3 ev.c ev.h ev.pod ev_epoll.c ev_kqueue.c ev_poll.c ev_port.c ev_select.c ev_vars.h ev_win32.c ev_wrap.h event.c event.h install-sh libev.m4 libtool ltmain.sh missing mkinstalldirs stamp-h1luajit
doc
bluequad-print.css bluequad.css contact.html ext_buffer.html ext_c_api.html ext_ffi.html ext_ffi_api.html ext_ffi_semantics.html ext_ffi_tutorial.html ext_jit.html ext_profiler.html extensions.html install.html luajit.html running.htmldynasm
dasm_arm.h dasm_arm.lua dasm_arm64.h dasm_arm64.lua dasm_mips.h dasm_mips.lua dasm_mips64.lua dasm_ppc.h dasm_ppc.lua dasm_proto.h dasm_x64.lua dasm_x86.h dasm_x86.lua dynasm.luasrc
host
.gitignore README buildvm.c buildvm.h buildvm_asm.c buildvm_fold.c buildvm_lib.c buildvm_libbc.h buildvm_peobj.c genlibbc.lua genminilua.lua genversion.lua minilua.cjit
.gitignore bc.lua bcsave.lua dis_arm.lua dis_arm64.lua dis_arm64be.lua dis_mips.lua dis_mips64.lua dis_mips64el.lua dis_mips64r6.lua dis_mips64r6el.lua dis_mipsel.lua dis_ppc.lua dis_x64.lua dis_x86.lua dump.lua p.lua v.lua zone.luawolfssl
.github
workflows
ada.yml arduino.yml async-examples.yml async.yml atecc608-sim.yml bind.yml cmake-autoconf.yml cmake.yml codespell.yml coverity-scan-fixes.yml cryptocb-only.yml curl.yml cyrus-sasl.yml disable-pk-algs.yml docker-Espressif.yml docker-OpenWrt.yml emnet-nonblock.yml fil-c.yml freertos-mem-track.yml gencertbuf.yml grpc.yml haproxy.yml hostap-vm.yml intelasm-c-fallback.yml ipmitool.yml jwt-cpp.yml krb5.yml libspdm.yml libssh2.yml libvncserver.yml linuxkm.yml macos-apple-native-cert-validation.yml mbedtls.sh mbedtls.yml membrowse-comment.yml membrowse-onboard.yml membrowse-report.yml memcached.sh memcached.yml mono.yml mosquitto.yml msmtp.yml msys2.yml multi-arch.yml multi-compiler.yml net-snmp.yml nginx.yml no-malloc.yml no-tls.yml nss.sh nss.yml ntp.yml ocsp.yml openldap.yml openssh.yml openssl-ech.yml opensslcoexist.yml openvpn.yml os-check.yml packaging.yml pam-ipmi.yml pq-all.yml pr-commit-check.yml psk.yml puf.yml python.yml rng-tools.yml rust-wrapper.yml se050-sim.yml smallStackSize.yml socat.yml softhsm.yml sssd.yml stm32-sim.yml stsafe-a120-sim.yml stunnel.yml symbol-prefixes.yml threadx.yml tls-anvil.yml trackmemory.yml watcomc.yml win-csharp-test.yml wolfCrypt-Wconversion.yml wolfboot-integration.yml wolfsm.yml xcode.yml zephyr-4.x.yml zephyr.ymlIDE
ARDUINO
Arduino_README_prepend.md README.md include.am keywords.txt library.properties.template wolfssl-arduino.cpp wolfssl-arduino.sh wolfssl.hECLIPSE
Espressif
ESP-IDF
examples
template
CMakeLists.txt Makefile README.md partitions_singleapp_large.csv sdkconfig.defaults sdkconfig.defaults.esp8266wolfssl_benchmark
VisualGDB
wolfssl_benchmark_IDF_v4.4_ESP32.sln wolfssl_benchmark_IDF_v4.4_ESP32.vgdbproj wolfssl_benchmark_IDF_v5_ESP32.sln wolfssl_benchmark_IDF_v5_ESP32.vgdbproj wolfssl_benchmark_IDF_v5_ESP32C3.sln wolfssl_benchmark_IDF_v5_ESP32C3.vgdbproj wolfssl_benchmark_IDF_v5_ESP32S3.sln wolfssl_benchmark_IDF_v5_ESP32S3.vgdbprojwolfssl_client
CMakeLists.txt Makefile README.md README_server_sm.md partitions_singleapp_large.csv sdkconfig.defaults sdkconfig.defaults.esp32c2 sdkconfig.defaults.esp8266 wolfssl_client_ESP8266.vgdbprojwolfssl_server
CMakeLists.txt Makefile README.md README_server_sm.md partitions_singleapp_large.csv sdkconfig.defaults sdkconfig.defaults.esp32c2 sdkconfig.defaults.esp8266 wolfssl_server_ESP8266.vgdbprojwolfssl_test
VisualGDB
wolfssl_test-IDF_v5_ESP32.sln wolfssl_test-IDF_v5_ESP32.vgdbproj wolfssl_test-IDF_v5_ESP32C3.sln wolfssl_test-IDF_v5_ESP32C3.vgdbproj wolfssl_test-IDF_v5_ESP32C6.sln wolfssl_test-IDF_v5_ESP32C6.vgdbproj wolfssl_test_IDF_v5_ESP32S3.sln wolfssl_test_IDF_v5_ESP32S3.vgdbprojGCC-ARM
Makefile Makefile.bench Makefile.client Makefile.common Makefile.server Makefile.static Makefile.test README.md include.am linker.ld linker_fips.ldIAR-EWARM
embOS
SAMV71_XULT
embOS_SAMV71_XULT_user_settings
user_settings.h user_settings_simple_example.h user_settings_verbose_example.hembOS_wolfcrypt_benchmark_SAMV71_XULT
README_wolfcrypt_benchmark wolfcrypt_benchmark.ewd wolfcrypt_benchmark.ewpINTIME-RTOS
Makefile README.md include.am libwolfssl.c libwolfssl.vcxproj user_settings.h wolfExamples.c wolfExamples.h wolfExamples.sln wolfExamples.vcxproj wolfssl-lib.sln wolfssl-lib.vcxprojMQX
Makefile README-jp.md README.md client-tls.c include.am server-tls.c user_config.h user_settings.hMSVS-2019-AZSPHERE
wolfssl_new_azsphere
.gitignore CMakeLists.txt CMakeSettings.json app_manifest.json applibs_versions.h launch.vs.json main.cNETOS
Makefile.wolfcrypt.inc README.md include.am user_settings.h user_settings.h-cert2425 user_settings.h-cert3389 wolfssl_netos_custom.cPlatformIO
examples
wolfssl_benchmark
CMakeLists.txt README.md platformio.ini sdkconfig.defaults wolfssl_benchmark.code-workspaceROWLEY-CROSSWORKS-ARM
Kinetis_FlashPlacement.xml README.md arm_startup.c benchmark_main.c hw.h include.am kinetis_hw.c retarget.c test_main.c user_settings.h wolfssl.hzp wolfssl_ltc.hzpRenesas
e2studio
RA6M3
README.md README_APRA6M_en.md README_APRA6M_jp.md include.amRX72N
EnvisionKit
Simple
README_EN.md README_JP.mdwolfssl_demo
key_data.c key_data.h user_settings.h wolfssl_demo.c wolfssl_demo.h wolfssl_tsip_unit_test.cSTM32Cube
README.md STM32_Benchmarks.md default_conf.ftl include.am main.c wolfssl_example.c wolfssl_example.hWIN
README.txt include.am test.vcxproj user_settings.h user_settings_dtls.h wolfssl-fips.sln wolfssl-fips.vcxprojWIN-SRTP-KDF-140-3
README.txt include.am resource.h test.vcxproj user_settings.h wolfssl-fips.rc wolfssl-fips.sln wolfssl-fips.vcxprojWIN10
README.txt include.am resource.h test.vcxproj user_settings.h wolfssl-fips.rc wolfssl-fips.sln wolfssl-fips.vcxprojXCODE
Benchmark
include.amXilinxSDK
README.md bench.sh combine.sh eclipse_formatter_profile.xml graph.sh include.am user_settings.h wolfssl_example.capple-universal
wolfssl-multiplatform
iotsafe
Makefile README.md ca-cert.c devices.c devices.h include.am main.c memory-tls.c startup.c target.ld user_settings.hmynewt
README.md apps.wolfcrypttest.pkg.yml crypto.wolfssl.pkg.yml crypto.wolfssl.syscfg.yml include.am setup.shcerts
1024
ca-cert.der ca-cert.pem ca-key.der ca-key.pem client-cert.der client-cert.pem client-key.der client-key.pem client-keyPub.der dh1024.der dh1024.pem dsa-pub-1024.pem dsa1024.der dsa1024.pem include.am rsa1024.der server-cert.der server-cert.pem server-key.der server-key.pemcrl
extra-crls
ca-int-cert-revoked.pem claim-root.pem crl_critical_entry.pem crlnum_57oct.pem crlnum_64oct.pem general-server-crl.pem large_crlnum.pem large_crlnum2.pemdilithium
bench_dilithium_level2_key.der bench_dilithium_level3_key.der bench_dilithium_level5_key.der include.amecc
bp256r1-key.der bp256r1-key.pem ca-secp256k1-cert.pem ca-secp256k1-key.pem client-bp256r1-cert.der client-bp256r1-cert.pem client-secp256k1-cert.der client-secp256k1-cert.pem genecc.sh include.am secp256k1-key.der secp256k1-key.pem secp256k1-param.pem secp256k1-privkey.der secp256k1-privkey.pem server-bp256r1-cert.der server-bp256r1-cert.pem server-secp256k1-cert.der server-secp256k1-cert.pem server2-secp256k1-cert.der server2-secp256k1-cert.pem wolfssl.cnf wolfssl_384.cnfed25519
ca-ed25519-key.der ca-ed25519-key.pem ca-ed25519-priv.der ca-ed25519-priv.pem ca-ed25519.der ca-ed25519.pem client-ed25519-key.der client-ed25519-key.pem client-ed25519-priv.der client-ed25519-priv.pem client-ed25519.der client-ed25519.pem eddsa-ed25519.der eddsa-ed25519.pem gen-ed25519-certs.sh gen-ed25519-keys.sh gen-ed25519.sh include.am root-ed25519-key.der root-ed25519-key.pem root-ed25519-priv.der root-ed25519-priv.pem root-ed25519.der root-ed25519.pem server-ed25519-cert.pem server-ed25519-key.der server-ed25519-key.pem server-ed25519-priv.der server-ed25519-priv.pem server-ed25519.der server-ed25519.pemed448
ca-ed448-key.der ca-ed448-key.pem ca-ed448-priv.der ca-ed448-priv.pem ca-ed448.der ca-ed448.pem client-ed448-key.der client-ed448-key.pem client-ed448-priv.der client-ed448-priv.pem client-ed448.der client-ed448.pem gen-ed448-certs.sh gen-ed448-keys.sh include.am root-ed448-key.der root-ed448-key.pem root-ed448-priv.der root-ed448-priv.pem root-ed448.der root-ed448.pem server-ed448-cert.pem server-ed448-key.der server-ed448-key.pem server-ed448-priv.der server-ed448-priv.pem server-ed448.der server-ed448.pemexternal
DigiCertGlobalRootCA.pem README.txt ca-digicert-ev.pem ca-globalsign-root.pem ca-google-root.pem ca_collection.pem include.amintermediate
ca_false_intermediate
gentestcert.sh int_ca.key server.key test_ca.key test_ca.pem test_int_not_cacert.pem test_sign_bynoca_srv.pem wolfssl_base.conf wolfssl_srv.conflms
bc_hss_L2_H5_W8_root.der bc_hss_L3_H5_W4_root.der bc_lms_chain_ca.der bc_lms_chain_leaf.der bc_lms_native_bc_root.der bc_lms_sha256_h10_w8_root.der bc_lms_sha256_h5_w4_root.der include.ammldsa
README.txt include.am mldsa44-cert.der mldsa44-cert.pem mldsa44-key.pem mldsa44_bare-priv.der mldsa44_bare-seed.der mldsa44_oqskeypair.der mldsa44_priv-only.der mldsa44_pub-spki.der mldsa44_seed-only.der mldsa44_seed-priv.der mldsa65-cert.der mldsa65-cert.pem mldsa65-key.pem mldsa65_bare-priv.der mldsa65_bare-seed.der mldsa65_oqskeypair.der mldsa65_priv-only.der mldsa65_pub-spki.der mldsa65_seed-only.der mldsa65_seed-priv.der mldsa87-cert.der mldsa87-cert.pem mldsa87-key.pem mldsa87_bare-priv.der mldsa87_bare-seed.der mldsa87_oqskeypair.der mldsa87_priv-only.der mldsa87_pub-spki.der mldsa87_seed-only.der mldsa87_seed-priv.derocsp
imposter-root-ca-cert.der imposter-root-ca-cert.pem imposter-root-ca-key.der imposter-root-ca-key.pem include.am index-ca-and-intermediate-cas.txt index-ca-and-intermediate-cas.txt.attr index-intermediate1-ca-issued-certs.txt index-intermediate1-ca-issued-certs.txt.attr index-intermediate2-ca-issued-certs.txt index-intermediate2-ca-issued-certs.txt.attr index-intermediate3-ca-issued-certs.txt index-intermediate3-ca-issued-certs.txt.attr intermediate1-ca-cert.der intermediate1-ca-cert.pem intermediate1-ca-key.der intermediate1-ca-key.pem intermediate2-ca-cert.der intermediate2-ca-cert.pem intermediate2-ca-key.der intermediate2-ca-key.pem intermediate3-ca-cert.der intermediate3-ca-cert.pem intermediate3-ca-key.der intermediate3-ca-key.pem ocsp-responder-cert.der ocsp-responder-cert.pem ocsp-responder-key.der ocsp-responder-key.pem openssl.cnf renewcerts-for-test.sh renewcerts.sh root-ca-cert.der root-ca-cert.pem root-ca-crl.pem root-ca-key.der root-ca-key.pem server1-cert.der server1-cert.pem server1-chain-noroot.pem server1-key.der server1-key.pem server2-cert.der server2-cert.pem server2-key.der server2-key.pem server3-cert.der server3-cert.pem server3-key.der server3-key.pem server4-cert.der server4-cert.pem server4-key.der server4-key.pem server5-cert.der server5-cert.pem server5-key.der server5-key.pem test-leaf-response.der test-multi-response.der test-response-nointern.der test-response-rsapss.der test-response.derp521
ca-p521-key.der ca-p521-key.pem ca-p521-priv.der ca-p521-priv.pem ca-p521.der ca-p521.pem client-p521-key.der client-p521-key.pem client-p521-priv.der client-p521-priv.pem client-p521.der client-p521.pem gen-p521-certs.sh gen-p521-keys.sh include.am root-p521-key.der root-p521-key.pem root-p521-priv.der root-p521-priv.pem root-p521.der root-p521.pem server-p521-cert.pem server-p521-key.der server-p521-key.pem server-p521-priv.der server-p521-priv.pem server-p521.der server-p521.pemrpk
client-cert-rpk.der client-ecc-cert-rpk.der include.am server-cert-rpk.der server-ecc-cert-rpk.derrsapss
ca-3072-rsapss-key.der ca-3072-rsapss-key.pem ca-3072-rsapss-priv.der ca-3072-rsapss-priv.pem ca-3072-rsapss.der ca-3072-rsapss.pem ca-rsapss-key.der ca-rsapss-key.pem ca-rsapss-priv.der ca-rsapss-priv.pem ca-rsapss.der ca-rsapss.pem client-3072-rsapss-key.der client-3072-rsapss-key.pem client-3072-rsapss-priv.der client-3072-rsapss-priv.pem client-3072-rsapss.der client-3072-rsapss.pem client-rsapss-key.der client-rsapss-key.pem client-rsapss-priv.der client-rsapss-priv.pem client-rsapss.der client-rsapss.pem gen-rsapss-keys.sh include.am renew-rsapss-certs.sh root-3072-rsapss-key.der root-3072-rsapss-key.pem root-3072-rsapss-priv.der root-3072-rsapss-priv.pem root-3072-rsapss.der root-3072-rsapss.pem root-rsapss-key.der root-rsapss-key.pem root-rsapss-priv.der root-rsapss-priv.pem root-rsapss.der root-rsapss.pem server-3072-rsapss-cert.pem server-3072-rsapss-key.der server-3072-rsapss-key.pem server-3072-rsapss-priv.der server-3072-rsapss-priv.pem server-3072-rsapss.der server-3072-rsapss.pem server-mix-rsapss-cert.pem server-rsapss-cert.pem server-rsapss-key.der server-rsapss-key.pem server-rsapss-priv.der server-rsapss-priv.pem server-rsapss.der server-rsapss.pemslhdsa
bench_slhdsa_sha2_128f_key.der bench_slhdsa_sha2_128s_key.der bench_slhdsa_sha2_192f_key.der bench_slhdsa_sha2_192s_key.der bench_slhdsa_sha2_256f_key.der bench_slhdsa_sha2_256s_key.der bench_slhdsa_shake128f_key.der bench_slhdsa_shake128s_key.der bench_slhdsa_shake192f_key.der bench_slhdsa_shake192s_key.der bench_slhdsa_shake256f_key.der bench_slhdsa_shake256s_key.der client-mldsa44-priv.pem client-mldsa44-sha2.der client-mldsa44-sha2.pem client-mldsa44-shake.der client-mldsa44-shake.pem gen-slhdsa-mldsa-certs.sh include.am root-slhdsa-sha2-128s-priv.der root-slhdsa-sha2-128s-priv.pem root-slhdsa-sha2-128s.der root-slhdsa-sha2-128s.pem root-slhdsa-shake-128s-priv.der root-slhdsa-shake-128s-priv.pem root-slhdsa-shake-128s.der root-slhdsa-shake-128s.pem server-mldsa44-priv.pem server-mldsa44-sha2.der server-mldsa44-sha2.pem server-mldsa44-shake.der server-mldsa44-shake.pemsm2
ca-sm2-key.der ca-sm2-key.pem ca-sm2-priv.der ca-sm2-priv.pem ca-sm2.der ca-sm2.pem client-sm2-key.der client-sm2-key.pem client-sm2-priv.der client-sm2-priv.pem client-sm2.der client-sm2.pem fix_sm2_spki.py gen-sm2-certs.sh gen-sm2-keys.sh include.am root-sm2-key.der root-sm2-key.pem root-sm2-priv.der root-sm2-priv.pem root-sm2.der root-sm2.pem self-sm2-cert.pem self-sm2-key.pem self-sm2-priv.pem server-sm2-cert.der server-sm2-cert.pem server-sm2-key.der server-sm2-key.pem server-sm2-priv.der server-sm2-priv.pem server-sm2.der server-sm2.pemstatickeys
dh-ffdhe2048-params.pem dh-ffdhe2048-pub.der dh-ffdhe2048-pub.pem dh-ffdhe2048.der dh-ffdhe2048.pem ecc-secp256r1.der ecc-secp256r1.pem gen-static.sh include.am x25519-pub.der x25519-pub.pem x25519.der x25519.pemtest
catalog.txt cert-bad-neg-int.der cert-bad-oid.der cert-bad-utf8.der cert-ext-ia.cfg cert-ext-ia.der cert-ext-ia.pem cert-ext-joi.cfg cert-ext-joi.der cert-ext-joi.pem cert-ext-mnc.der cert-ext-multiple.cfg cert-ext-multiple.der cert-ext-multiple.pem cert-ext-nc-combined.der cert-ext-nc-combined.pem cert-ext-nc.cfg cert-ext-nc.der cert-ext-nc.pem cert-ext-ncdns.der cert-ext-ncdns.pem cert-ext-ncip.der cert-ext-ncip.pem cert-ext-ncmixed.der cert-ext-ncmulti.der cert-ext-ncmulti.pem cert-ext-ncrid.der cert-ext-ncrid.pem cert-ext-nct.cfg cert-ext-nct.der cert-ext-nct.pem cert-ext-ndir-exc.cfg cert-ext-ndir-exc.der cert-ext-ndir-exc.pem cert-ext-ndir.cfg cert-ext-ndir.der cert-ext-ndir.pem cert-ext-ns.der cert-over-max-altnames.cfg cert-over-max-altnames.der cert-over-max-altnames.pem cert-over-max-nc.cfg cert-over-max-nc.der cert-over-max-nc.pem client-ecc-cert-ski.hex cn-ip-literal.der cn-ip-wildcard.der crit-cert.pem crit-key.pem dh1024.der dh1024.pem dh512.der dh512.pem digsigku.pem encrypteddata.msg gen-badsig.sh gen-ext-certs.sh gen-testcerts.sh include.am kari-keyid-cms.msg ktri-keyid-cms.msg ossl-trusted-cert.pem server-badaltname.der server-badaltname.pem server-badaltnull.der server-badaltnull.pem server-badcn.der server-badcn.pem server-badcnnull.der server-badcnnull.pem server-cert-ecc-badsig.der server-cert-ecc-badsig.pem server-cert-rsa-badsig.der server-cert-rsa-badsig.pem server-duplicate-policy.pem server-garbage.der server-garbage.pem server-goodalt.der server-goodalt.pem server-goodaltwild.der server-goodaltwild.pem server-goodcn.der server-goodcn.pem server-goodcnwild.der server-goodcnwild.pem server-localhost.der server-localhost.pem smime-test-canon.p7s smime-test-multipart-badsig.p7s smime-test-multipart.p7s smime-test.p7stest-pathlen
assemble-chains.sh chainA-ICA1-key.pem chainA-ICA1-pathlen0.pem chainA-assembled.pem chainA-entity-key.pem chainA-entity.pem chainB-ICA1-key.pem chainB-ICA1-pathlen0.pem chainB-ICA2-key.pem chainB-ICA2-pathlen1.pem chainB-assembled.pem chainB-entity-key.pem chainB-entity.pem chainC-ICA1-key.pem chainC-ICA1-pathlen1.pem chainC-assembled.pem chainC-entity-key.pem chainC-entity.pem chainD-ICA1-key.pem chainD-ICA1-pathlen127.pem chainD-assembled.pem chainD-entity-key.pem chainD-entity.pem chainE-ICA1-key.pem chainE-ICA1-pathlen128.pem chainE-assembled.pem chainE-entity-key.pem chainE-entity.pem chainF-ICA1-key.pem chainF-ICA1-pathlen1.pem chainF-ICA2-key.pem chainF-ICA2-pathlen0.pem chainF-assembled.pem chainF-entity-key.pem chainF-entity.pem chainG-ICA1-key.pem chainG-ICA1-pathlen0.pem chainG-ICA2-key.pem chainG-ICA2-pathlen1.pem chainG-ICA3-key.pem chainG-ICA3-pathlen99.pem chainG-ICA4-key.pem chainG-ICA4-pathlen5.pem chainG-ICA5-key.pem chainG-ICA5-pathlen20.pem chainG-ICA6-key.pem chainG-ICA6-pathlen10.pem chainG-ICA7-key.pem chainG-ICA7-pathlen100.pem chainG-assembled.pem chainG-entity-key.pem chainG-entity.pem chainH-ICA1-key.pem chainH-ICA1-pathlen0.pem chainH-ICA2-key.pem chainH-ICA2-pathlen2.pem chainH-ICA3-key.pem chainH-ICA3-pathlen2.pem chainH-ICA4-key.pem chainH-ICA4-pathlen2.pem chainH-assembled.pem chainH-entity-key.pem chainH-entity.pem chainI-ICA1-key.pem chainI-ICA1-no_pathlen.pem chainI-ICA2-key.pem chainI-ICA2-no_pathlen.pem chainI-ICA3-key.pem chainI-ICA3-pathlen2.pem chainI-assembled.pem chainI-entity-key.pem chainI-entity.pem chainJ-ICA1-key.pem chainJ-ICA1-no_pathlen.pem chainJ-ICA2-key.pem chainJ-ICA2-no_pathlen.pem chainJ-ICA3-key.pem chainJ-ICA3-no_pathlen.pem chainJ-ICA4-key.pem chainJ-ICA4-pathlen2.pem chainJ-assembled.pem chainJ-entity-key.pem chainJ-entity.pem include.am refreshkeys.shtest-serial0
ee_normal.pem ee_serial0.pem generate_certs.sh include.am intermediate_serial0.pem root_serial0.pem root_serial0_key.pem selfsigned_nonca_serial0.pemxmss
bc_xmss_chain_ca.der bc_xmss_chain_leaf.der bc_xmss_sha2_10_256_root.der bc_xmss_sha2_16_256_root.der bc_xmssmt_sha2_20_2_256_root.der bc_xmssmt_sha2_20_4_256_root.der bc_xmssmt_sha2_40_8_256_root.der include.amcmake
Config.cmake.in README.md config.in functions.cmake include.am options.h.in wolfssl-config-version.cmake.in wolfssl-targets.cmake.indebian
changelog.in control.in copyright include.am libwolfssl-dev.install libwolfssl.install rules.indoc
dox_comments
header_files
aes.h arc4.h ascon.h asn.h asn_public.h blake2.h bn.h camellia.h chacha.h chacha20_poly1305.h cmac.h coding.h compress.h cryptocb.h curve25519.h curve448.h des3.h dh.h doxygen_groups.h doxygen_pages.h dsa.h ecc.h eccsi.h ed25519.h ed448.h error-crypt.h evp.h hash.h hmac.h iotsafe.h kdf.h logging.h md2.h md4.h md5.h memory.h ocsp.h pem.h pkcs11.h pkcs7.h poly1305.h psa.h puf.h pwdbased.h quic.h random.h ripemd.h rsa.h sakke.h sha.h sha256.h sha3.h sha512.h signature.h siphash.h srp.h ssl.h tfm.h types.h wc_encrypt.h wc_port.h wc_she.h wc_slhdsa.h wolfio.hheader_files-ja
aes.h arc4.h ascon.h asn.h asn_public.h blake2.h bn.h camellia.h chacha.h chacha20_poly1305.h cmac.h coding.h compress.h cryptocb.h curve25519.h curve448.h des3.h dh.h doxygen_groups.h doxygen_pages.h dsa.h ecc.h eccsi.h ed25519.h ed448.h error-crypt.h evp.h hash.h hmac.h iotsafe.h kdf.h logging.h md2.h md4.h md5.h memory.h ocsp.h pem.h pkcs11.h pkcs7.h poly1305.h psa.h pwdbased.h quic.h random.h ripemd.h rsa.h sakke.h sha.h sha256.h sha3.h sha512.h signature.h siphash.h srp.h ssl.h tfm.h types.h wc_encrypt.h wc_port.h wolfio.hexamples
async
Makefile README.md async_client.c async_server.c async_tls.c async_tls.h include.am user_settings.hconfigs
README.md include.am user_settings_EBSnet.h user_settings_all.h user_settings_arduino.h user_settings_baremetal.h user_settings_ca.h user_settings_curve25519nonblock.h user_settings_dtls13.h user_settings_eccnonblock.h user_settings_espressif.h user_settings_fipsv2.h user_settings_fipsv5.h user_settings_min_ecc.h user_settings_openssl_compat.h user_settings_pkcs7.h user_settings_platformio.h user_settings_pq.h user_settings_rsa_only.h user_settings_stm32.h user_settings_template.h user_settings_tls12.h user_settings_tls13.h user_settings_wolfboot_keytools.h user_settings_wolfssh.h user_settings_wolftpm.hechoclient
echoclient.c echoclient.h echoclient.sln echoclient.vcproj echoclient.vcxproj include.am quitlinuxkm
Kbuild Makefile README.md get_thread_size.c include.am linuxkm-fips-hash-wrapper.sh linuxkm-fips-hash.c linuxkm_memory.c linuxkm_memory.h linuxkm_wc_port.h lkcapi_aes_glue.c lkcapi_dh_glue.c lkcapi_ecdh_glue.c lkcapi_ecdsa_glue.c lkcapi_glue.c lkcapi_rsa_glue.c lkcapi_sha_glue.c module_exports.c.template module_hooks.c pie_redirect_table.c wolfcrypt.lds x86_vector_register_glue.cm4
ax_add_am_macro.m4 ax_am_jobserver.m4 ax_am_macros.m4 ax_append_compile_flags.m4 ax_append_flag.m4 ax_append_link_flags.m4 ax_append_to_file.m4 ax_atomic.m4 ax_bsdkm.m4 ax_check_compile_flag.m4 ax_check_link_flag.m4 ax_compiler_version.m4 ax_count_cpus.m4 ax_create_generic_config.m4 ax_debug.m4 ax_file_escapes.m4 ax_harden_compiler_flags.m4 ax_linuxkm.m4 ax_print_to_file.m4 ax_pthread.m4 ax_require_defined.m4 ax_tls.m4 ax_vcs_checkout.m4 hexversion.m4 lib_socket_nsl.m4 visibility.m4mqx
wolfcrypt_benchmark
ReferencedRSESystems.xml wolfcrypt_benchmark_twrk70f120m_Int_Flash_DDRData_Debug_PnE_U-MultiLink.launch wolfcrypt_benchmark_twrk70f120m_Int_Flash_DDRData_Release_PnE_U-MultiLink.launch wolfcrypt_benchmark_twrk70f120m_Int_Flash_SramData_Debug_JTrace.jlink wolfcrypt_benchmark_twrk70f120m_Int_Flash_SramData_Debug_JTrace.launch wolfcrypt_benchmark_twrk70f120m_Int_Flash_SramData_Debug_PnE_U-MultiLink.launch wolfcrypt_benchmark_twrk70f120m_Int_Flash_SramData_Release_PnE_U-MultiLink.launchwolfcrypt_test
ReferencedRSESystems.xml wolfcrypt_test_twrk70f120m_Int_Flash_DDRData_Debug_PnE_U-MultiLink.launch wolfcrypt_test_twrk70f120m_Int_Flash_DDRData_Release_PnE_U-MultiLink.launch wolfcrypt_test_twrk70f120m_Int_Flash_SramData_Debug_JTrace.jlink wolfcrypt_test_twrk70f120m_Int_Flash_SramData_Debug_JTrace.launch wolfcrypt_test_twrk70f120m_Int_Flash_SramData_Debug_PnE_U-MultiLink.launch wolfcrypt_test_twrk70f120m_Int_Flash_SramData_Release_PnE_U-MultiLink.launchwolfssl_client
ReferencedRSESystems.xml wolfssl_client_twrk70f120m_Int_Flash_DDRData_Debug_PnE_U-MultiLink.launch wolfssl_client_twrk70f120m_Int_Flash_DDRData_Release_PnE_U-MultiLink.launch wolfssl_client_twrk70f120m_Int_Flash_SramData_Debug_JTrace.jlink wolfssl_client_twrk70f120m_Int_Flash_SramData_Debug_JTrace.launch wolfssl_client_twrk70f120m_Int_Flash_SramData_Debug_PnE_U-MultiLink.launch wolfssl_client_twrk70f120m_Int_Flash_SramData_Release_PnE_U-MultiLink.launchscripts
aria-cmake-build-test.sh asn1_oid_sum.pl benchmark.test benchmark_compare.sh cleanup_testfiles.sh crl-gen-openssl.test crl-revoked.test dertoc.pl dtls.test dtlscid.test external.test google.test include.am makedistsmall.sh memtest.sh ocsp-responder-openssl-interop.test ocsp-stapling-with-ca-as-responder.test ocsp-stapling-with-wolfssl-responder.test ocsp-stapling.test ocsp-stapling2.test ocsp-stapling_tls13multi.test ocsp.test openssl.test openssl_srtp.test pem.test ping.test pkcallbacks.test psk.test resume.test rsapss.test sniffer-gen.sh sniffer-ipv6.pcap sniffer-static-rsa.pcap sniffer-testsuite.test sniffer-tls12-keylog.out sniffer-tls12-keylog.pcap sniffer-tls12-keylog.sslkeylog sniffer-tls13-dh-resume.pcap sniffer-tls13-dh.pcap sniffer-tls13-ecc-resume.pcap sniffer-tls13-ecc.pcap sniffer-tls13-hrr.pcap sniffer-tls13-keylog.out sniffer-tls13-keylog.pcap sniffer-tls13-keylog.sslkeylog sniffer-tls13-x25519-resume.pcap sniffer-tls13-x25519.pcap stm32l4-v4_0_1_build.sh tls13.test trusted_peer.test unit.test.in user_settings_asm.shsrc
bio.c conf.c crl.c dtls.c dtls13.c include.am internal.c keys.c ocsp.c pk.c pk_ec.c pk_rsa.c quic.c sniffer.c ssl.c ssl_api_cert.c ssl_api_crl_ocsp.c ssl_api_pk.c ssl_asn1.c ssl_bn.c ssl_certman.c ssl_crypto.c ssl_ech.c ssl_load.c ssl_misc.c ssl_p7p12.c ssl_sess.c ssl_sk.c tls.c tls13.c wolfio.c x509.c x509_str.ctests
api
api.h api_decl.h create_ocsp_test_blobs.py include.am test_aes.c test_aes.h test_arc4.c test_arc4.h test_ascon.c test_ascon.h test_ascon_kats.h test_asn.c test_asn.h test_blake2.c test_blake2.h test_camellia.c test_camellia.h test_certman.c test_certman.h test_chacha.c test_chacha.h test_chacha20_poly1305.c test_chacha20_poly1305.h test_cmac.c test_cmac.h test_curve25519.c test_curve25519.h test_curve448.c test_curve448.h test_des3.c test_des3.h test_dh.c test_dh.h test_digest.h test_dsa.c test_dsa.h test_dtls.c test_dtls.h test_ecc.c test_ecc.h test_ed25519.c test_ed25519.h test_ed448.c test_ed448.h test_evp.c test_evp.h test_evp_cipher.c test_evp_cipher.h test_evp_digest.c test_evp_digest.h test_evp_pkey.c test_evp_pkey.h test_hash.c test_hash.h test_hmac.c test_hmac.h test_md2.c test_md2.h test_md4.c test_md4.h test_md5.c test_md5.h test_mldsa.c test_mldsa.h test_mlkem.c test_mlkem.h test_ocsp.c test_ocsp.h test_ocsp_test_blobs.h test_ossl_asn1.c test_ossl_asn1.h test_ossl_bio.c test_ossl_bio.h test_ossl_bn.c test_ossl_bn.h test_ossl_cipher.c test_ossl_cipher.h test_ossl_dgst.c test_ossl_dgst.h test_ossl_dh.c test_ossl_dh.h test_ossl_dsa.c test_ossl_dsa.h test_ossl_ec.c test_ossl_ec.h test_ossl_ecx.c test_ossl_ecx.h test_ossl_mac.c test_ossl_mac.h test_ossl_obj.c test_ossl_obj.h test_ossl_p7p12.c test_ossl_p7p12.h test_ossl_pem.c test_ossl_pem.h test_ossl_rand.c test_ossl_rand.h test_ossl_rsa.c test_ossl_rsa.h test_ossl_sk.c test_ossl_sk.h test_ossl_x509.c test_ossl_x509.h test_ossl_x509_acert.c test_ossl_x509_acert.h test_ossl_x509_crypto.c test_ossl_x509_crypto.h test_ossl_x509_ext.c test_ossl_x509_ext.h test_ossl_x509_info.c test_ossl_x509_info.h test_ossl_x509_io.c test_ossl_x509_io.h test_ossl_x509_lu.c test_ossl_x509_lu.h test_ossl_x509_name.c test_ossl_x509_name.h test_ossl_x509_pk.c test_ossl_x509_pk.h test_ossl_x509_str.c test_ossl_x509_str.h test_ossl_x509_vp.c test_ossl_x509_vp.h test_pkcs12.c test_pkcs12.h test_pkcs7.c test_pkcs7.h test_poly1305.c test_poly1305.h test_random.c test_random.h test_rc2.c test_rc2.h test_ripemd.c test_ripemd.h test_rsa.c test_rsa.h test_sha.c test_sha.h test_sha256.c test_sha256.h test_sha3.c test_sha3.h test_sha512.c test_sha512.h test_she.c test_she.h test_signature.c test_signature.h test_slhdsa.c test_slhdsa.h test_sm2.c test_sm2.h test_sm3.c test_sm3.h test_sm4.c test_sm4.h test_tls.c test_tls.h test_tls13.c test_tls13.h test_tls_ext.c test_tls_ext.h test_wc_encrypt.c test_wc_encrypt.h test_wolfmath.c test_wolfmath.h test_x509.c test_x509.hwolfcrypt
benchmark
README.md benchmark-VS2022.sln benchmark-VS2022.vcxproj benchmark-VS2022.vcxproj.user benchmark.c benchmark.h benchmark.sln benchmark.vcproj benchmark.vcxproj include.amsrc
port
Espressif
esp_crt_bundle
README.md cacrt_all.pem cacrt_deprecated.pem cacrt_local.pem esp_crt_bundle.c gen_crt_bundle.py pio_install_cryptography.pyRenesas
README.md renesas_common.c renesas_fspsm_aes.c renesas_fspsm_rsa.c renesas_fspsm_sha.c renesas_fspsm_util.c renesas_rx64_hw_sha.c renesas_rx64_hw_util.c renesas_tsip_aes.c renesas_tsip_rsa.c renesas_tsip_sha.c renesas_tsip_util.carm
armv8-32-aes-asm.S armv8-32-aes-asm_c.c armv8-32-chacha-asm.S armv8-32-chacha-asm_c.c armv8-32-curve25519.S armv8-32-curve25519_c.c armv8-32-mlkem-asm.S armv8-32-mlkem-asm_c.c armv8-32-poly1305-asm.S armv8-32-poly1305-asm_c.c armv8-32-sha256-asm.S armv8-32-sha256-asm_c.c armv8-32-sha3-asm.S armv8-32-sha3-asm_c.c armv8-32-sha512-asm.S armv8-32-sha512-asm_c.c armv8-aes-asm.S armv8-aes-asm_c.c armv8-aes.c armv8-chacha-asm.S armv8-chacha-asm_c.c armv8-curve25519.S armv8-curve25519_c.c armv8-mlkem-asm.S armv8-mlkem-asm_c.c armv8-poly1305-asm.S armv8-poly1305-asm_c.c armv8-sha256-asm.S armv8-sha256-asm_c.c armv8-sha256.c armv8-sha3-asm.S armv8-sha3-asm_c.c armv8-sha512-asm.S armv8-sha512-asm_c.c armv8-sha512.c cryptoCell.c cryptoCellHash.c thumb2-aes-asm.S thumb2-aes-asm_c.c thumb2-chacha-asm.S thumb2-chacha-asm_c.c thumb2-curve25519.S thumb2-curve25519_c.c thumb2-mlkem-asm.S thumb2-mlkem-asm_c.c thumb2-poly1305-asm.S thumb2-poly1305-asm_c.c thumb2-sha256-asm.S thumb2-sha256-asm_c.c thumb2-sha3-asm.S thumb2-sha3-asm_c.c thumb2-sha512-asm.S thumb2-sha512-asm_c.ccaam
README.md caam_aes.c caam_doc.pdf caam_driver.c caam_error.c caam_integrity.c caam_qnx.c caam_sha.c wolfcaam_aes.c wolfcaam_cmac.c wolfcaam_ecdsa.c wolfcaam_fsl_nxp.c wolfcaam_hash.c wolfcaam_hmac.c wolfcaam_init.c wolfcaam_qnx.c wolfcaam_rsa.c wolfcaam_seco.c wolfcaam_x25519.cdevcrypto
README.md devcrypto_aes.c devcrypto_ecdsa.c devcrypto_hash.c devcrypto_hmac.c devcrypto_rsa.c devcrypto_x25519.c wc_devcrypto.criscv
riscv-64-aes.c riscv-64-chacha.c riscv-64-poly1305.c riscv-64-sha256.c riscv-64-sha3.c riscv-64-sha512.cwolfssl
openssl
aes.h asn1.h asn1t.h bio.h bn.h buffer.h camellia.h cmac.h cms.h compat_types.h conf.h crypto.h des.h dh.h dsa.h ec.h ec25519.h ec448.h ecdh.h ecdsa.h ed25519.h ed448.h engine.h err.h evp.h fips_rand.h hmac.h include.am kdf.h lhash.h md4.h md5.h modes.h obj_mac.h objects.h ocsp.h opensslconf.h opensslv.h ossl_typ.h pem.h pkcs12.h pkcs7.h rand.h rc4.h ripemd.h rsa.h safestack.h sha.h sha3.h srp.h ssl.h ssl23.h stack.h tls1.h txt_db.h ui.h x509.h x509_vfy.h x509v3.hwolfcrypt
port
Renesas
renesas-fspsm-crypt.h renesas-fspsm-types.h renesas-rx64-hw-crypt.h renesas-tsip-crypt.h renesas_cmn.h renesas_fspsm_internal.h renesas_sync.h renesas_tsip_internal.h renesas_tsip_types.hcaam
caam_driver.h caam_error.h caam_qnx.h wolfcaam.h wolfcaam_aes.h wolfcaam_cmac.h wolfcaam_ecdsa.h wolfcaam_fsl_nxp.h wolfcaam_hash.h wolfcaam_qnx.h wolfcaam_rsa.h wolfcaam_seco.h wolfcaam_sha.h wolfcaam_x25519.hwrapper
Ada
examples
src
aes_verify_main.adb rsa_verify_main.adb sha256_main.adb spark_sockets.adb spark_sockets.ads spark_terminal.adb spark_terminal.ads tls_client.adb tls_client.ads tls_client_main.adb tls_server.adb tls_server.ads tls_server_main.adbtests
src
aes_bindings_tests.adb aes_bindings_tests.ads rsa_verify_bindings_tests.adb rsa_verify_bindings_tests.ads sha256_bindings_tests.adb sha256_bindings_tests.ads tests.adbCSharp
wolfSSL-Example-IOCallbacks
App.config wolfSSL-Example-IOCallbacks.cs wolfSSL-Example-IOCallbacks.csprojwolfSSL-TLS-ServerThreaded
App.config wolfSSL-TLS-ServerThreaded.cs wolfSSL-TLS-ServerThreaded.csprojrust
wolfssl-wolfcrypt
src
aes.rs blake2.rs chacha20_poly1305.rs cmac.rs cmac_mac.rs curve25519.rs dh.rs dilithium.rs ecc.rs ecdsa.rs ed25519.rs ed448.rs fips.rs hkdf.rs hmac.rs hmac_mac.rs kdf.rs lib.rs lms.rs mlkem.rs mlkem_kem.rs pbkdf2_password_hash.rs prf.rs random.rs rsa.rs rsa_pkcs1v15.rs sha.rs sha_digest.rs sys.rstests
test_aes.rs test_blake2.rs test_chacha20_poly1305.rs test_cmac.rs test_cmac_mac.rs test_curve25519.rs test_dh.rs test_dilithium.rs test_ecc.rs test_ecdsa.rs test_ed25519.rs test_ed448.rs test_hkdf.rs test_hmac.rs test_hmac_mac.rs test_kdf.rs test_lms.rs test_mlkem.rs test_mlkem_kem.rs test_pbkdf2_password_hash.rs test_prf.rs test_random.rs test_rsa.rs test_rsa_pkcs1v15.rs test_sha.rs test_sha_digest.rs test_wolfcrypt.rszephyr
samples
wolfssl_benchmark
CMakeLists.txt README install_test.sh prj.conf sample.yaml zephyr_legacy.conf zephyr_v4.1.confwolfssl_test
CMakeLists.txt README install_test.sh prj-no-malloc.conf prj.conf sample.yaml zephyr_legacy.conf zephyr_v4.1.conf
wolfssl/wolfcrypt/src/pkcs7.c
raw
1/* pkcs7.c
2 *
3 * Copyright (C) 2006-2026 wolfSSL Inc.
4 *
5 * This file is part of wolfSSL.
6 *
7 * wolfSSL is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 3 of the License, or
10 * (at your option) any later version.
11 *
12 * wolfSSL is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA
20 */
21
22/*
23 * PKCS#7 Build Options:
24 *
25 * Core:
26 * HAVE_PKCS7: Enable PKCS#7 support default: off
27 * NO_PKCS7_STREAM: Disable PKCS#7 streaming mode default: off
28 * NO_PKCS7_ENCRYPTED_DATA: Disable PKCS#7 EncryptedData type default: off
29 * NO_PKCS7_COMPRESSED_DATA: Disable PKCS#7 CompressedData type default: off
30 * WC_PKCS7_STREAM_DEBUG: Enable PKCS#7 stream debug output default: off
31 * WOLFSSL_PKCS7_MAX_DECOMPRESSION: Max decompression size default: off
32 *
33 * Callbacks:
34 * HAVE_PKCS7_RSA_RAW_SIGN_CALLBACK: Custom RSA raw sign callback default: off
35 * HAVE_PKCS7_ECC_RAW_SIGN_CALLBACK: Custom ECC raw sign callback default: off
36 *
37 * Key Derivation:
38 * HAVE_X963_KDF: Enable ANSI X9.63 KDF default: off
39 */
40
41#include <wolfssl/wolfcrypt/libwolfssl_sources.h>
42
43#ifdef HAVE_PKCS7
44
45#include <wolfssl/wolfcrypt/pkcs7.h>
46#include <wolfssl/wolfcrypt/hash.h>
47#ifndef NO_HMAC
48 #include <wolfssl/wolfcrypt/hmac.h>
49#endif
50#ifndef NO_RSA
51 #include <wolfssl/wolfcrypt/rsa.h>
52#endif
53#ifndef RSA_PSS_SALT_LEN_DEFAULT
54 #define RSA_PSS_SALT_LEN_DEFAULT (-1)
55#endif
56#if defined(WC_RSA_PSS) && !defined(NO_RSA)
57 #if (defined(HAVE_FIPS) && \
58 (!defined(HAVE_FIPS_VERSION) || (HAVE_FIPS_VERSION < 2))) || \
59 (defined(HAVE_SELFTEST) && \
60 (!defined(HAVE_SELFTEST_VERSION) || (HAVE_SELFTEST_VERSION < 2)))
61 #ifndef WC_MGF1NONE
62 #define WC_MGF1NONE 0
63 #define WC_MGF1SHA1 26
64 #define WC_MGF1SHA224 4
65 #define WC_MGF1SHA256 1
66 #define WC_MGF1SHA384 2
67 #define WC_MGF1SHA512 3
68 #define WC_MGF1SHA512_224 5
69 #define WC_MGF1SHA512_256 6
70 #endif
71 #endif
72#endif
73#ifdef HAVE_ECC
74 #include <wolfssl/wolfcrypt/ecc.h>
75#endif
76#ifdef HAVE_LIBZ
77 #include <wolfssl/wolfcrypt/compress.h>
78#endif
79#ifndef NO_PWDBASED
80 #include <wolfssl/wolfcrypt/pwdbased.h>
81#endif
82#ifdef NO_INLINE
83 #include <wolfssl/wolfcrypt/misc.h>
84#else
85 #define WOLFSSL_MISC_INCLUDED
86 #include <wolfcrypt/src/misc.c>
87#endif
88
89/* direction for processing, encoding or decoding */
90typedef enum {
91 WC_PKCS7_ENCODE,
92 WC_PKCS7_DECODE
93} pkcs7Direction;
94
95#define NO_USER_CHECK 0
96
97/* holds information about the signers */
98struct PKCS7SignerInfo {
99 int version;
100 int sidType; /* CMS_ISSUER_AND_SERIAL_NUMBER or CMS_SKID */
101 byte *sid;
102 word32 sidSz;
103};
104
105
106#ifndef WOLFSSL_PKCS7_MAX_DECOMPRESSION
107 /* 1031 comes from "Maximum Compression Factor" in the zlib tech document,
108 * typical compression is from 2:1 to 5:1 but there is rare cases where
109 * 1030.3:1 could happen (like a file with all 0's)
110 */
111 #define WOLFSSL_PKCS7_MAX_DECOMPRESSION 1031
112#endif
113
114#ifndef NO_PKCS7_STREAM
115
116/* Hard upper bound on a single PKCS7 streaming buffer allocation. Guards
117 * wc_PKCS7_GrowStream against attacker-controlled ASN.1 lengths that were
118 * parsed with NO_USER_CHECK and would otherwise drive allocations up to
119 * around 2GB (e.g. via a forged RecipientInfo SET length). 16 MB is well above
120 * any legitimate RecipientInfo / encoded-attribute size but small enough
121 * that a forged length fails allocation on constrained targets and is
122 * rejected on larger ones. */
123#ifndef WOLFSSL_PKCS7_MAX_STREAM_ALLOC
124 #define WOLFSSL_PKCS7_MAX_STREAM_ALLOC (16 * 1024 * 1024)
125#endif
126
127#define MAX_PKCS7_STREAM_BUFFER 256
128struct PKCS7State {
129 byte* tmpCert;
130 byte* bufferPt;
131 byte* key;
132 byte* nonce; /* stored nonce */
133 byte* aad; /* additional data for AEAD algos */
134 byte* tag; /* tag data for AEAD algos */
135 byte* content;
136 byte* buffer; /* main internal read buffer */
137
138 wc_HashAlg hashAlg;
139 enum wc_HashType hashType;
140 int cntIdfCnt; /* count of in-definite length in content info */
141
142 /* stack variables to store for when returning */
143 word32 varOne;
144 int varTwo;
145 int varThree;
146
147 word32 vers;
148 word32 idx; /* index read into current input buffer */
149 word32 maxLen; /* sanity cap on maximum amount of data to allow
150 * needed for GetSequence and other calls */
151 word32 length; /* amount of data stored */
152 word32 bufferSz; /* size of internal buffer */
153 word32 expected; /* next amount of data expected, if needed */
154 word32 totalRd; /* total amount of bytes read */
155 word32 nonceSz; /* size of nonce stored */
156 word32 aadSz; /* size of additional AEAD data */
157 word32 tagSz; /* size of tag for AEAD */
158 word32 icvSz; /* expected ICV/MAC size from AlgoID parameter */
159 word32 contentSz;
160 word32 currContIdx; /* index of current content */
161 word32 currContSz; /* size of current content */
162 word32 currContRmnSz; /* remaining size of current content */
163 word32 accumContSz; /* size of accumulated content size */
164 int recipientSz; /* size of recipient set */
165 byte tmpIv[MAX_CONTENT_IV_SIZE]; /* store IV if needed */
166#ifdef WC_PKCS7_STREAM_DEBUG
167 word32 peakUsed; /* most bytes used for struct at any one time */
168 word32 peakRead; /* most bytes used by read buffer */
169#endif
170 WC_BITFIELD multi:1; /* flag for if content is in multiple parts */
171 WC_BITFIELD flagOne:1;
172 WC_BITFIELD detached:1; /* flag to indicate detached signature is present */
173 WC_BITFIELD noContent:1;/* indicates content isn't included in bundle */
174 WC_BITFIELD degenerate:1;
175 WC_BITFIELD indefLen:1; /* flag to indicate indef-length encoding used */
176};
177
178
179/* creates a PKCS7State structure and returns 0 on success */
180static int wc_PKCS7_CreateStream(wc_PKCS7* pkcs7)
181{
182 WOLFSSL_MSG("creating PKCS7 stream structure");
183 pkcs7->stream = (PKCS7State*)XMALLOC(sizeof(PKCS7State), pkcs7->heap,
184 DYNAMIC_TYPE_PKCS7);
185 if (pkcs7->stream == NULL) {
186 return MEMORY_E;
187 }
188 XMEMSET(pkcs7->stream, 0, sizeof(PKCS7State));
189#ifdef WC_PKCS7_STREAM_DEBUG
190 printf("\nCreating new PKCS#7 stream %p\n", pkcs7->stream);
191#endif
192 return 0;
193}
194
195
196static void wc_PKCS7_ResetStream(wc_PKCS7* pkcs7)
197{
198 if (pkcs7 != NULL && pkcs7->stream != NULL) {
199#ifdef WC_PKCS7_STREAM_DEBUG
200 /* collect final data point in case more was read right before reset */
201 if (pkcs7->stream->length > pkcs7->stream->peakRead) {
202 pkcs7->stream->peakRead = pkcs7->stream->length;
203 }
204 if (pkcs7->stream->bufferSz + pkcs7->stream->aadSz +
205 pkcs7->stream->nonceSz + pkcs7->stream->tagSz >
206 pkcs7->stream->peakUsed) {
207 pkcs7->stream->peakUsed = pkcs7->stream->bufferSz +
208 pkcs7->stream->aadSz + pkcs7->stream->nonceSz +
209 pkcs7->stream->tagSz;
210 }
211
212 /* print out debugging statistics */
213 if (pkcs7->stream->peakUsed > 0 || pkcs7->stream->peakRead > 0) {
214 printf("PKCS#7 STREAM:\n\tPeak heap used by struct = %d"
215 "\n\tPeak read buffer bytes = %d"
216 "\n\tTotal bytes read = %d"
217 "\n",
218 pkcs7->stream->peakUsed, pkcs7->stream->peakRead,
219 pkcs7->stream->totalRd);
220 }
221 printf("PKCS#7 stream reset : Address [%p]\n", pkcs7->stream);
222 #endif
223
224 /* free any buffers that may be allocated */
225 if (pkcs7->stream->aad != NULL && pkcs7->stream->aadSz > 0)
226 ForceZero(pkcs7->stream->aad, pkcs7->stream->aadSz);
227 XFREE(pkcs7->stream->aad, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
228 XFREE(pkcs7->stream->tag, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
229 XFREE(pkcs7->stream->nonce, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
230 XFREE(pkcs7->stream->buffer, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
231 /* stream->key is always allocated with MAX_ENCRYPTED_KEY_SZ */
232 if (pkcs7->stream->key != NULL)
233 ForceZero(pkcs7->stream->key, MAX_ENCRYPTED_KEY_SZ);
234 XFREE(pkcs7->stream->key, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
235 pkcs7->stream->aad = NULL;
236 pkcs7->stream->tag = NULL;
237 pkcs7->stream->nonce = NULL;
238 pkcs7->stream->buffer = NULL;
239 pkcs7->stream->key = NULL;
240
241 /* reset values, note that content and tmpCert are saved */
242 pkcs7->stream->maxLen = 0;
243 pkcs7->stream->length = 0;
244 pkcs7->stream->idx = 0;
245 pkcs7->stream->expected = 0;
246 pkcs7->stream->totalRd = 0;
247 pkcs7->stream->bufferSz = 0;
248
249 pkcs7->stream->multi = 0;
250 pkcs7->stream->flagOne = 0;
251 pkcs7->stream->detached = 0;
252 pkcs7->stream->varOne = 0;
253 pkcs7->stream->varTwo = 0;
254 pkcs7->stream->varThree = 0;
255 pkcs7->stream->noContent = 0;
256 pkcs7->stream->indefLen = 0;
257 pkcs7->stream->cntIdfCnt = 0;
258 pkcs7->stream->currContIdx = 0;
259 pkcs7->stream->currContSz = 0;
260 pkcs7->stream->currContRmnSz= 0;
261 pkcs7->stream->accumContSz = 0;
262 pkcs7->stream->contentSz = 0;
263 pkcs7->stream->hashType = WC_HASH_TYPE_NONE;
264 }
265}
266
267
268static void wc_PKCS7_FreeStream(wc_PKCS7* pkcs7)
269{
270 if (pkcs7 != NULL && pkcs7->stream != NULL) {
271 wc_PKCS7_ResetStream(pkcs7);
272
273 XFREE(pkcs7->stream->content, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
274 XFREE(pkcs7->stream->tmpCert, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
275 pkcs7->stream->content = NULL;
276 pkcs7->stream->tmpCert = NULL;
277 XFREE(pkcs7->stream, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
278 pkcs7->stream = NULL;
279 }
280}
281
282
283/* used to increase the max size for internal buffer
284 * returns 0 on success */
285static int wc_PKCS7_GrowStream(wc_PKCS7* pkcs7, word32 newSz)
286{
287 byte* pt;
288
289 /* Guard against attacker-controlled ASN.1 lengths reaching this
290 * allocation. Several callers parse lengths with NO_USER_CHECK and
291 * pass them here unvalidated (e.g. wc_PKCS7_ParseToRecipientInfoSet
292 * on a forged RecipientInfo SET header). */
293 if (newSz > WOLFSSL_PKCS7_MAX_STREAM_ALLOC) {
294 WOLFSSL_MSG("PKCS7 streaming allocation exceeds maximum");
295 return BUFFER_E;
296 }
297
298 pt = (byte*)XMALLOC(newSz, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
299 if (pt == NULL) {
300 return MEMORY_E;
301 }
302
303 if (pkcs7->stream->buffer != NULL && pkcs7->stream->bufferSz > 0) {
304 XMEMCPY(pt, pkcs7->stream->buffer, pkcs7->stream->bufferSz);
305 }
306
307#ifdef WC_PKCS7_STREAM_DEBUG
308 printf("PKCS7 increasing internal stream buffer %d -> %d\n",
309 pkcs7->stream->bufferSz, newSz);
310#endif
311 pkcs7->stream->bufferSz = newSz;
312 XFREE(pkcs7->stream->buffer, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
313 pkcs7->stream->buffer = pt;
314 return 0;
315}
316
317
318/* pt gets set to the buffer that is holding data in the case that stream struct
319 * is used.
320 *
321 * Sets idx to be the current offset into "pt" buffer
322 * returns 0 on success
323 */
324static int wc_PKCS7_AddDataToStream(wc_PKCS7* pkcs7, byte* in, word32 inSz,
325 word32 expected, byte** pt, word32* idx)
326{
327 word32 rdSz = pkcs7->stream->idx;
328
329 /* If the input size minus current index into input buffer is greater than
330 * the expected size then use the input buffer. If data is already stored
331 * in stream buffer or if there is not enough input data available then use
332 * the stream buffer. */
333 if (inSz - rdSz >= expected && pkcs7->stream->length == 0) {
334 /* storing input buffer is not needed */
335 *pt = in; /* reset in case previously used internal buffer */
336 *idx = rdSz;
337 return 0;
338 }
339
340 /* is there enough stored in buffer already? */
341 if (pkcs7->stream->length >= expected) {
342 *idx = 0; /* start reading from beginning of stream buffer */
343 *pt = pkcs7->stream->buffer;
344 return 0;
345 }
346
347 /* check if all data has been read from input */
348 if (rdSz >= inSz) {
349 /* no more input to read, reset input index and request more data */
350 pkcs7->stream->idx = 0;
351 return WC_NO_ERR_TRACE(WC_PKCS7_WANT_READ_E);
352 }
353
354 /* try to store input data into stream buffer */
355 if (inSz - rdSz > 0 && pkcs7->stream->length < expected) {
356 word32 len = min(inSz - rdSz, expected - pkcs7->stream->length);
357
358 /* sanity check that the input buffer is not internal buffer */
359 if (in == pkcs7->stream->buffer) {
360 return WC_PKCS7_WANT_READ_E;
361 }
362
363 /* check if internal buffer size needs to be increased */
364 if ((len + pkcs7->stream->length > pkcs7->stream->bufferSz) ||
365 (pkcs7->stream->buffer == NULL))
366 {
367 int ret = wc_PKCS7_GrowStream(pkcs7, expected);
368 if (ret < 0) {
369 return ret;
370 }
371 }
372 XMEMCPY(pkcs7->stream->buffer + pkcs7->stream->length, in + rdSz, len);
373 pkcs7->stream->length += len;
374 pkcs7->stream->idx += len;
375 pkcs7->stream->totalRd += len;
376 }
377
378#ifdef WC_PKCS7_STREAM_DEBUG
379 /* collects memory usage for debugging */
380 if (pkcs7->stream->length > pkcs7->stream->peakRead) {
381 pkcs7->stream->peakRead = pkcs7->stream->length;
382 }
383 if (pkcs7->stream->bufferSz + pkcs7->stream->aadSz + pkcs7->stream->nonceSz +
384 pkcs7->stream->tagSz > pkcs7->stream->peakUsed) {
385 pkcs7->stream->peakUsed = pkcs7->stream->bufferSz +
386 pkcs7->stream->aadSz + pkcs7->stream->nonceSz + pkcs7->stream->tagSz;
387 }
388#endif
389
390 /* if not enough data was read in then request more */
391 if (pkcs7->stream->length < expected) {
392 pkcs7->stream->idx = 0;
393 return WC_NO_ERR_TRACE(WC_PKCS7_WANT_READ_E);
394 }
395
396 /* adjust pointer to read from stored buffer */
397 *idx = 0;
398 *pt = pkcs7->stream->buffer;
399 return 0;
400}
401
402
403/* setter function for stored variables */
404static void wc_PKCS7_StreamStoreVar(wc_PKCS7* pkcs7, word32 var1, int var2,
405 int var3)
406{
407 if (pkcs7 != NULL && pkcs7->stream != NULL) {
408 pkcs7->stream->varOne = var1;
409 pkcs7->stream->varTwo = var2;
410 pkcs7->stream->varThree = var3;
411 }
412}
413
414/* Tries to peek at the SEQ and get the length
415 * returns 0 on success
416 */
417static int wc_PKCS7_SetMaxStream(wc_PKCS7* pkcs7, byte* in, word32 defSz)
418{
419 /* check there is a buffer to read from */
420 if (pkcs7) {
421 int length = 0, ret;
422 word32 idx = 0, maxIdx;
423 byte* pt;
424
425 if (pkcs7->stream->length > 0) {
426 length = (int)pkcs7->stream->length;
427 pt = pkcs7->stream->buffer;
428 }
429 else {
430 length = (int)defSz;
431 pt = in;
432 }
433 maxIdx = (word32)length;
434
435 if (length < MAX_SEQ_SZ) {
436 WOLFSSL_MSG("PKCS7 Error not enough data for SEQ peek");
437 return 0;
438 }
439
440 if ((ret = GetSequence_ex(pt, &idx, &length, maxIdx, NO_USER_CHECK))
441 < 0) {
442 return ret;
443 }
444
445 if (length == 0 && ret == 0) {
446 idx = 0;
447 WOLFSSL_MSG("PKCS7 found indef SEQ with peek");
448 }
449
450 pkcs7->stream->maxLen = (word32)length + idx;
451
452 if (pkcs7->stream->maxLen == 0) {
453 pkcs7->stream->maxLen = defSz;
454 }
455 }
456
457 return 0;
458}
459
460
461/* getter function for stored variables */
462static void wc_PKCS7_StreamGetVar(wc_PKCS7* pkcs7, word32* var1, int* var2,
463 int* var3)
464{
465 if (pkcs7 != NULL && pkcs7->stream != NULL) {
466 if (var1 != NULL) *var1 = pkcs7->stream->varOne;
467 if (var2 != NULL) *var2 = pkcs7->stream->varTwo;
468 if (var3 != NULL) *var3 = pkcs7->stream->varThree;
469 }
470}
471
472
473/* common update of index and total read after section complete
474 * returns 0 on success */
475static int wc_PKCS7_StreamEndCase(wc_PKCS7* pkcs7, word32* tmpIdx, word32* idx)
476{
477 int ret = 0;
478
479 if (pkcs7->stream->length > 0) {
480 if (pkcs7->stream->length < *idx) {
481 WOLFSSL_MSG("PKCS7 read too much data from internal buffer");
482 ret = BUFFER_E;
483 }
484 else {
485 XMEMMOVE(pkcs7->stream->buffer, pkcs7->stream->buffer + *idx,
486 pkcs7->stream->length - *idx);
487 pkcs7->stream->length -= *idx;
488 }
489 }
490 else {
491 pkcs7->stream->totalRd += *idx - *tmpIdx;
492 pkcs7->stream->idx = *idx; /* adjust index into input buffer */
493 *tmpIdx = *idx;
494 }
495
496 return ret;
497}
498#endif /* NO_PKCS7_STREAM */
499
500#ifdef WC_PKCS7_STREAM_DEBUG
501/* used to print out human readable state for debugging */
502static const char* wc_PKCS7_GetStateName(int in)
503{
504 switch (in) {
505 case WC_PKCS7_START: return "WC_PKCS7_START";
506
507 case WC_PKCS7_STAGE2: return "WC_PKCS7_STAGE2";
508 case WC_PKCS7_STAGE3: return "WC_PKCS7_STAGE3";
509 case WC_PKCS7_STAGE4: return "WC_PKCS7_STAGE4";
510 case WC_PKCS7_STAGE5: return "WC_PKCS7_STAGE5";
511 case WC_PKCS7_STAGE6: return "WC_PKCS7_STAGE6";
512
513 /* parse info set */
514 case WC_PKCS7_INFOSET_START: return "WC_PKCS7_INFOSET_START";
515 case WC_PKCS7_INFOSET_BER: return "WC_PKCS7_INFOSET_BER";
516 case WC_PKCS7_INFOSET_STAGE1: return "WC_PKCS7_INFOSET_STAGE1";
517 case WC_PKCS7_INFOSET_STAGE2: return "WC_PKCS7_INFOSET_STAGE2";
518 case WC_PKCS7_INFOSET_END: return "WC_PKCS7_INFOSET_END";
519
520 /* decode enveloped data */
521 case WC_PKCS7_ENV_2: return "WC_PKCS7_ENV_2";
522 case WC_PKCS7_ENV_3: return "WC_PKCS7_ENV_3";
523 case WC_PKCS7_ENV_4: return "WC_PKCS7_ENV_4";
524 case WC_PKCS7_ENV_5: return "WC_PKCS7_ENV_5";
525
526 /* decode auth enveloped */
527 case WC_PKCS7_AUTHENV_2: return "WC_PKCS7_AUTHENV_2";
528 case WC_PKCS7_AUTHENV_3: return "WC_PKCS7_AUTHENV_3";
529 case WC_PKCS7_AUTHENV_4: return "WC_PKCS7_AUTHENV_4";
530 case WC_PKCS7_AUTHENV_5: return "WC_PKCS7_AUTHENV_5";
531 case WC_PKCS7_AUTHENV_6: return "WC_PKCS7_AUTHENV_6";
532 case WC_PKCS7_AUTHENV_ATRB: return "WC_PKCS7_AUTHENV_ATRB";
533 case WC_PKCS7_AUTHENV_ATRBEND: return "WC_PKCS7_AUTHENV_ATRBEND";
534 case WC_PKCS7_AUTHENV_7: return "WC_PKCS7_AUTHENV_7";
535
536 /* decryption state types */
537 case WC_PKCS7_DECRYPT_KTRI: return "WC_PKCS7_DECRYPT_KTRI";
538 case WC_PKCS7_DECRYPT_KTRI_2: return "WC_PKCS7_DECRYPT_KTRI_2";
539 case WC_PKCS7_DECRYPT_KTRI_3: return "WC_PKCS7_DECRYPT_KTRI_3";
540
541 case WC_PKCS7_DECRYPT_KARI: return "WC_PKCS7_DECRYPT_KARI";
542 case WC_PKCS7_DECRYPT_KEKRI: return "WC_PKCS7_DECRYPT_KEKRI";
543 case WC_PKCS7_DECRYPT_PWRI: return "WC_PKCS7_DECRYPT_PWRI";
544 case WC_PKCS7_DECRYPT_ORI: return "WC_PKCS7_DECRYPT_ORI";
545 case WC_PKCS7_DECRYPT_DONE: return "WC_PKCS7_DECRYPT_DONE";
546
547 case WC_PKCS7_VERIFY_STAGE2: return "WC_PKCS7_VERIFY_STAGE2";
548 case WC_PKCS7_VERIFY_STAGE3: return "WC_PKCS7_VERIFY_STAGE3";
549 case WC_PKCS7_VERIFY_STAGE4: return "WC_PKCS7_VERIFY_STAGE4";
550 case WC_PKCS7_VERIFY_STAGE5: return "WC_PKCS7_VERIFY_STAGE5";
551 case WC_PKCS7_VERIFY_STAGE6: return "WC_PKCS7_VERIFY_STAGE6";
552 case WC_PKCS7_VERIFY_STAGE7: return "WC_PKCS7_VERIFY_STAGE7";
553
554 default:
555 return "Unknown state";
556 }
557}
558#endif
559
560/* Used to change the PKCS7 state. Having state change as a function allows
561 * for easier debugging */
562static void wc_PKCS7_ChangeState(wc_PKCS7* pkcs7, int newState)
563{
564#ifdef WC_PKCS7_STREAM_DEBUG
565 printf("\tChanging from state [%02d] %s to [%02d] %s\n",
566 pkcs7->state, wc_PKCS7_GetStateName(pkcs7->state),
567 newState, wc_PKCS7_GetStateName(newState));
568#endif
569 pkcs7->state = (word32)newState;
570}
571
572#define MAX_PKCS7_DIGEST_SZ (MAX_SEQ_SZ + MAX_ALGO_SZ + \
573 MAX_OCTET_STR_SZ + WC_MAX_DIGEST_SIZE)
574
575
576/* placed ASN.1 contentType OID into *output, return idx on success,
577 * 0 upon failure */
578static int wc_SetContentType(int pkcs7TypeOID, byte* output, word32 outputSz)
579{
580 /* PKCS#7 content types, RFC 2315, section 14 */
581 static const byte pkcs7[] =
582 { 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x07 };
583 static const byte data[] =
584 { 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x07, 0x01 };
585 static const byte signedData[] =
586 { 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x07, 0x02};
587 static const byte envelopedData[] =
588 { 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x07, 0x03 };
589 static const byte authEnvelopedData[] =
590 { 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x09, 0x10, 0x01, 0x17};
591 static const byte signedAndEnveloped[] =
592 { 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x07, 0x04 };
593 static const byte digestedData[] =
594 { 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x07, 0x05 };
595#ifndef NO_PKCS7_ENCRYPTED_DATA
596 static const byte encryptedData[] =
597 { 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x07, 0x06 };
598#endif
599 /* FirmwarePkgData (1.2.840.113549.1.9.16.1.16), RFC 4108 */
600 static const byte firmwarePkgData[] =
601 { 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x09, 0x10, 0x01, 0x10 };
602#if defined(HAVE_LIBZ) && !defined(NO_PKCS7_COMPRESSED_DATA)
603 /* id-ct-compressedData (1.2.840.113549.1.9.16.1.9), RFC 3274 */
604 static const byte compressedData[] =
605 { 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x09, 0x10, 0x01, 0x09 };
606#endif
607
608#if !defined(NO_PWDBASED) && !defined(NO_SHA)
609 static const byte pwriKek[] =
610 { 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x09, 0x10, 0x03, 0x09 };
611 static const byte pbkdf2[] =
612 { 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x05, 0x0C };
613#endif
614
615 word32 idSz, idx = 0;
616 word32 typeSz = 0;
617 const byte* typeName = 0;
618 byte ID_Length[MAX_LENGTH_SZ];
619
620 switch (pkcs7TypeOID) {
621 case PKCS7_MSG:
622 typeSz = sizeof(pkcs7);
623 typeName = pkcs7;
624 break;
625
626 case DATA:
627 typeSz = sizeof(data);
628 typeName = data;
629 break;
630
631 case SIGNED_DATA:
632 typeSz = sizeof(signedData);
633 typeName = signedData;
634 break;
635
636 case ENVELOPED_DATA:
637 typeSz = sizeof(envelopedData);
638 typeName = envelopedData;
639 break;
640
641 case AUTH_ENVELOPED_DATA:
642 typeSz = sizeof(authEnvelopedData);
643 typeName = authEnvelopedData;
644 break;
645
646 case SIGNED_AND_ENVELOPED_DATA:
647 typeSz = sizeof(signedAndEnveloped);
648 typeName = signedAndEnveloped;
649 break;
650
651 case DIGESTED_DATA:
652 typeSz = sizeof(digestedData);
653 typeName = digestedData;
654 break;
655
656#ifndef NO_PKCS7_ENCRYPTED_DATA
657 case ENCRYPTED_DATA:
658 typeSz = sizeof(encryptedData);
659 typeName = encryptedData;
660 break;
661#endif
662#if defined(HAVE_LIBZ) && !defined(NO_PKCS7_COMPRESSED_DATA)
663 case COMPRESSED_DATA:
664 typeSz = sizeof(compressedData);
665 typeName = compressedData;
666 break;
667#endif
668 case FIRMWARE_PKG_DATA:
669 typeSz = sizeof(firmwarePkgData);
670 typeName = firmwarePkgData;
671 break;
672
673#if !defined(NO_PWDBASED) && !defined(NO_SHA)
674 case PWRI_KEK_WRAP:
675 typeSz = sizeof(pwriKek);
676 typeName = pwriKek;
677 break;
678
679 case PBKDF2_OID:
680 typeSz = sizeof(pbkdf2);
681 typeName = pbkdf2;
682 break;
683#endif
684
685 default:
686 WOLFSSL_MSG("Unknown PKCS#7 Type");
687 return 0;
688 };
689
690 if (outputSz < (MAX_LENGTH_SZ + 1 + typeSz)) {
691 WOLFSSL_MSG("CMS content type buffer too small");
692 return BAD_FUNC_ARG;
693 }
694
695 idSz = SetLength(typeSz, ID_Length);
696 output[idx++] = ASN_OBJECT_ID;
697 XMEMCPY(output + idx, ID_Length, idSz);
698 idx += idSz;
699 XMEMCPY(output + idx, typeName, typeSz);
700 idx += typeSz;
701
702 return (int)idx;
703}
704
705
706/* get ASN.1 contentType OID sum, return 0 on success, <0 on failure */
707static int wc_GetContentType(const byte* input, word32* inOutIdx, word32* oid,
708 word32 maxIdx)
709{
710 WOLFSSL_ENTER("wc_GetContentType");
711 if (GetObjectId(input, inOutIdx, oid, oidIgnoreType, maxIdx) < 0) {
712 WOLFSSL_LEAVE("wc_GetContentType", ASN_PARSE_E);
713 return ASN_PARSE_E;
714 }
715
716 return 0;
717}
718
719
720/* return block size for algorithm represented by oid, or <0 on error */
721static int wc_PKCS7_GetOIDBlockSize(int oid)
722{
723 int blockSz;
724
725 switch (oid) {
726#ifndef NO_AES
727 #ifdef WOLFSSL_AES_128
728 #ifdef HAVE_AES_CBC
729 case AES128CBCb:
730 #endif
731 #ifdef HAVE_AESGCM
732 case AES128GCMb:
733 #endif
734 #ifdef HAVE_AESCCM
735 case AES128CCMb:
736 #endif
737 #endif
738 #ifdef WOLFSSL_AES_192
739 #ifdef HAVE_AES_CBC
740 case AES192CBCb:
741 #endif
742 #ifdef HAVE_AESGCM
743 case AES192GCMb:
744 #endif
745 #ifdef HAVE_AESCCM
746 case AES192CCMb:
747 #endif
748 #endif
749 #ifdef WOLFSSL_AES_256
750 #ifdef HAVE_AES_CBC
751 case AES256CBCb:
752 #endif
753 #ifdef HAVE_AESGCM
754 case AES256GCMb:
755 #endif
756 #ifdef HAVE_AESCCM
757 case AES256CCMb:
758 #endif
759 #endif
760 blockSz = WC_AES_BLOCK_SIZE;
761 break;
762#endif /* !NO_AES */
763
764#ifndef NO_DES3
765 case DESb:
766 case DES3b:
767 blockSz = DES_BLOCK_SIZE;
768 break;
769#endif
770 default:
771 WOLFSSL_MSG("Unsupported content cipher type");
772 return ALGO_ID_E;
773 };
774
775 return blockSz;
776}
777
778
779/* get key size for algorithm represented by oid, or <0 on error */
780static int wc_PKCS7_GetOIDKeySize(int oid)
781{
782 int blockKeySz;
783
784 switch (oid) {
785#ifndef NO_AES
786 #ifdef WOLFSSL_AES_128
787 #ifdef HAVE_AES_CBC
788 case AES128CBCb:
789 #endif
790 #ifdef HAVE_AESGCM
791 case AES128GCMb:
792 #endif
793 #ifdef HAVE_AESCCM
794 case AES128CCMb:
795 #endif
796 case AES128_WRAP:
797 blockKeySz = 16;
798 break;
799 #endif
800 #ifdef WOLFSSL_AES_192
801 #ifdef HAVE_AES_CBC
802 case AES192CBCb:
803 #endif
804 #ifdef HAVE_AESGCM
805 case AES192GCMb:
806 #endif
807 #ifdef HAVE_AESCCM
808 case AES192CCMb:
809 #endif
810 case AES192_WRAP:
811 blockKeySz = 24;
812 break;
813 #endif
814 #ifdef WOLFSSL_AES_256
815 #ifdef HAVE_AES_CBC
816 case AES256CBCb:
817 #endif
818 #ifdef HAVE_AESGCM
819 case AES256GCMb:
820 #endif
821 #ifdef HAVE_AESCCM
822 case AES256CCMb:
823 #endif
824 case AES256_WRAP:
825 blockKeySz = 32;
826 break;
827 #endif
828#endif /* !NO_AES */
829
830#ifndef NO_DES3
831 case DESb:
832 blockKeySz = DES_KEYLEN;
833 break;
834 case DES3b:
835 blockKeySz = DES3_KEYLEN;
836 break;
837#endif
838 default:
839 WOLFSSL_MSG("Unsupported content cipher type");
840 return ALGO_ID_E;
841 };
842
843 return blockKeySz;
844}
845
846
847wc_PKCS7* wc_PKCS7_New(void* heap, int devId)
848{
849 wc_PKCS7* pkcs7 = (wc_PKCS7*)XMALLOC(sizeof(wc_PKCS7), heap, DYNAMIC_TYPE_PKCS7);
850 if (pkcs7) {
851 XMEMSET(pkcs7, 0, sizeof(wc_PKCS7));
852 if (wc_PKCS7_Init(pkcs7, heap, devId) == 0) {
853 pkcs7->isDynamic = 1;
854 }
855 else {
856 XFREE(pkcs7, heap, DYNAMIC_TYPE_PKCS7);
857 pkcs7 = NULL;
858 }
859 }
860 return pkcs7;
861}
862
863/* This is to initialize a PKCS7 structure. It sets all values to 0 and can be
864 * used to set the heap hint.
865 *
866 * pkcs7 PKCS7 structure to initialize
867 * heap memory heap hint for PKCS7 structure to use
868 * devId currently not used but a place holder for async operations
869 *
870 * returns 0 on success or a negative value for failure
871 */
872int wc_PKCS7_Init(wc_PKCS7* pkcs7, void* heap, int devId)
873{
874 word16 isDynamic;
875
876 WOLFSSL_ENTER("wc_PKCS7_Init");
877
878 if (pkcs7 == NULL) {
879 return BAD_FUNC_ARG;
880 }
881
882 isDynamic = pkcs7->isDynamic;
883 XMEMSET(pkcs7, 0, sizeof(wc_PKCS7));
884 pkcs7->isDynamic = (isDynamic != 0);
885#ifdef WOLFSSL_HEAP_TEST
886 pkcs7->heap = (void*)WOLFSSL_HEAP_TEST;
887#else
888 pkcs7->heap = heap;
889#endif
890 pkcs7->devId = devId;
891
892 return 0;
893}
894
895#ifdef WC_ASN_UNKNOWN_EXT_CB
896void wc_PKCS7_SetUnknownExtCallback(wc_PKCS7* pkcs7, wc_UnknownExtCallback cb)
897{
898 if (pkcs7 != NULL) {
899 pkcs7->unknownExtCallback = cb;
900 }
901}
902#endif
903
904/* Certificate structure holding der pointer, size, and pointer to next
905 * Pkcs7Cert struct. Used when creating SignedData types with multiple
906 * certificates. */
907struct Pkcs7Cert {
908 byte* der;
909 word32 derSz;
910 Pkcs7Cert* next;
911};
912
913
914/* Linked list of ASN.1 encoded RecipientInfos */
915struct Pkcs7EncodedRecip {
916 byte recip[MAX_RECIP_SZ];
917 word32 recipSz;
918 int recipType;
919 int recipVersion;
920 Pkcs7EncodedRecip* next;
921};
922
923
924/* free all members of Pkcs7Cert linked list */
925static void wc_PKCS7_FreeCertSet(wc_PKCS7* pkcs7)
926{
927 Pkcs7Cert* curr = NULL;
928 Pkcs7Cert* next = NULL;
929
930 if (pkcs7 == NULL)
931 return;
932
933 curr = pkcs7->certList;
934 pkcs7->certList = NULL;
935
936 while (curr != NULL) {
937 next = curr->next;
938 curr->next = NULL;
939 XFREE(curr, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
940 curr = next;
941 }
942
943 return;
944}
945
946
947/* Get total size of all recipients in recipient list.
948 *
949 * Returns total size of recipients, or negative upon error */
950static int wc_PKCS7_GetRecipientListSize(wc_PKCS7* pkcs7)
951{
952 word32 totalSz = 0;
953 Pkcs7EncodedRecip* tmp = NULL;
954
955 if (pkcs7 == NULL)
956 return BAD_FUNC_ARG;
957
958 tmp = pkcs7->recipList;
959
960 while (tmp != NULL) {
961 totalSz += tmp->recipSz;
962 tmp = tmp->next;
963 }
964
965 return (int)totalSz;
966}
967
968
969/* free all members of Pkcs7EncodedRecip linked list */
970static void wc_PKCS7_FreeEncodedRecipientSet(wc_PKCS7* pkcs7)
971{
972 Pkcs7EncodedRecip* curr = NULL;
973 Pkcs7EncodedRecip* next = NULL;
974
975 if (pkcs7 == NULL)
976 return;
977
978 curr = pkcs7->recipList;
979 pkcs7->recipList = NULL;
980
981 while (curr != NULL) {
982 next = curr->next;
983 curr->next = NULL;
984 XFREE(curr, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
985 curr = next;
986 }
987
988 return;
989}
990
991
992/* search through RecipientInfo list for specific type.
993 * return 1 if ANY recipient of type specified is present, otherwise
994 * return 0 */
995static int wc_PKCS7_RecipientListIncludesType(wc_PKCS7* pkcs7, int type)
996{
997 Pkcs7EncodedRecip* tmp = NULL;
998
999 if (pkcs7 == NULL)
1000 return BAD_FUNC_ARG;
1001
1002 tmp = pkcs7->recipList;
1003
1004 while (tmp != NULL) {
1005 if (tmp->recipType == type)
1006 return 1;
1007
1008 tmp = tmp->next;
1009 }
1010
1011 return 0;
1012}
1013
1014
1015/* searches through RecipientInfo list, returns 1 if all structure
1016 * versions are set to 0, otherwise returns 0 */
1017static int wc_PKCS7_RecipientListVersionsAllZero(wc_PKCS7* pkcs7)
1018{
1019 Pkcs7EncodedRecip* tmp = NULL;
1020
1021 if (pkcs7 == NULL)
1022 return BAD_FUNC_ARG;
1023
1024 tmp = pkcs7->recipList;
1025
1026 while (tmp != NULL) {
1027 if (tmp->recipVersion != 0)
1028 return 0;
1029
1030 tmp = tmp->next;
1031 }
1032
1033 return 1;
1034}
1035
1036/* Verify RSA/ECC key is correctly formatted, used as sanity check after
1037 * import of key/cert.
1038 *
1039 * keyOID - key OID (ex: RSAk, ECDSAk)
1040 * key - key in DER
1041 * keySz - size of key, octets
1042 *
1043 * Returns 0 on success, negative on error */
1044static int wc_PKCS7_CheckPublicKeyDer(wc_PKCS7* pkcs7, int keyOID,
1045 const byte* key, word32 keySz)
1046{
1047 int ret = 0;
1048 word32 scratch = 0;
1049#ifdef WOLFSSL_SMALL_STACK
1050 #ifndef NO_RSA
1051 RsaKey* rsa;
1052 #endif
1053 #ifdef HAVE_ECC
1054 ecc_key* ecc;
1055 #endif
1056#else
1057 #ifndef NO_RSA
1058 RsaKey rsa[1];
1059 #endif
1060 #ifdef HAVE_ECC
1061 ecc_key ecc[1];
1062 #endif
1063#endif
1064
1065 if (pkcs7 == NULL || key == NULL || keySz == 0) {
1066 return BAD_FUNC_ARG;
1067 }
1068
1069#ifdef WOLFSSL_SMALL_STACK
1070 #ifndef NO_RSA
1071 rsa = (RsaKey*)XMALLOC(sizeof(RsaKey), pkcs7->heap,
1072 DYNAMIC_TYPE_TMP_BUFFER);
1073 if (rsa == NULL) {
1074 return MEMORY_E;
1075 }
1076 #endif
1077
1078 #ifdef HAVE_ECC
1079 ecc = (ecc_key*)XMALLOC(sizeof(ecc_key), pkcs7->heap,
1080 DYNAMIC_TYPE_TMP_BUFFER);
1081 if (ecc == NULL) {
1082 #ifndef NO_RSA
1083 XFREE(rsa, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
1084 #endif
1085 return MEMORY_E;
1086 }
1087 #endif
1088#endif
1089
1090 switch (keyOID) {
1091#ifndef NO_RSA
1092 #ifdef WC_RSA_PSS
1093 case RSAPSSk:
1094 /* RSA-PSS cert: public key is same RSA format as RSAk */
1095 FALL_THROUGH;
1096 #endif
1097 case RSAk:
1098 ret = wc_InitRsaKey_ex(rsa, pkcs7->heap, pkcs7->devId);
1099 if (ret != 0) {
1100 break;
1101 }
1102
1103 /* Try to decode public key as sanity check. wc_CheckRsaKey()
1104 only checks private key not public. */
1105 ret = wc_RsaPublicKeyDecode(key, &scratch, rsa, keySz);
1106 wc_FreeRsaKey(rsa);
1107
1108 break;
1109#endif
1110#ifdef HAVE_ECC
1111 case ECDSAk:
1112 ret = wc_ecc_init_ex(ecc, pkcs7->heap, pkcs7->devId);
1113 if (ret != 0) {
1114 break;
1115 }
1116
1117 /* Try to decode public key and check with wc_ecc_check_key() */
1118 ret = wc_EccPublicKeyDecode(key, &scratch, ecc, keySz);
1119 #if defined(WOLFSSL_VALIDATE_ECC_IMPORT)
1120 if (ret == 0) {
1121 ret = wc_ecc_check_key(ecc);
1122 }
1123 #endif
1124 wc_ecc_free(ecc);
1125
1126 break;
1127#endif
1128 }
1129
1130#ifdef WOLFSSL_SMALL_STACK
1131 #ifndef NO_RSA
1132 XFREE(rsa, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
1133 #endif
1134 #ifdef HAVE_ECC
1135 XFREE(ecc, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
1136 #endif
1137#endif
1138
1139 return ret;
1140}
1141
1142
1143/* Init PKCS7 struct with recipient cert, decode into DecodedCert
1144 * NOTE: keeps previously set pkcs7 heap hint, devId and isDynamic */
1145int wc_PKCS7_InitWithCert(wc_PKCS7* pkcs7, byte* derCert, word32 derCertSz)
1146{
1147 int ret = 0;
1148 void* heap;
1149 int devId;
1150 Pkcs7Cert* cert;
1151 Pkcs7Cert* lastCert;
1152#ifdef WC_ASN_UNKNOWN_EXT_CB
1153 wc_UnknownExtCallback cb;
1154#endif
1155
1156 if (pkcs7 == NULL || (derCert == NULL && derCertSz != 0)) {
1157 return BAD_FUNC_ARG;
1158 }
1159
1160 heap = pkcs7->heap;
1161 devId = pkcs7->devId;
1162 cert = pkcs7->certList;
1163#ifdef WC_ASN_UNKNOWN_EXT_CB
1164 cb = pkcs7->unknownExtCallback; /* save / restore callback */
1165#endif
1166 ret = wc_PKCS7_Init(pkcs7, heap, devId);
1167 if (ret != 0)
1168 return ret;
1169
1170#ifdef WC_ASN_UNKNOWN_EXT_CB
1171 pkcs7->unknownExtCallback = cb;
1172#endif
1173 pkcs7->certList = cert;
1174
1175 if (derCert != NULL && derCertSz > 0) {
1176#ifdef WOLFSSL_SMALL_STACK
1177 DecodedCert* dCert;
1178
1179 dCert = (DecodedCert*)XMALLOC(sizeof(DecodedCert), pkcs7->heap,
1180 DYNAMIC_TYPE_DCERT);
1181 if (dCert == NULL)
1182 return MEMORY_E;
1183#else
1184 DecodedCert dCert[1];
1185#endif
1186
1187 pkcs7->singleCert = derCert;
1188 pkcs7->singleCertSz = derCertSz;
1189 pkcs7->cert[0] = derCert;
1190 pkcs7->certSz[0] = derCertSz;
1191
1192 /* create new Pkcs7Cert for recipient, freed during cleanup */
1193 cert = (Pkcs7Cert*)XMALLOC(sizeof(Pkcs7Cert), pkcs7->heap,
1194 DYNAMIC_TYPE_PKCS7);
1195 if (cert == NULL) {
1196 WC_FREE_VAR_EX(dCert, pkcs7->heap, DYNAMIC_TYPE_DCERT);
1197 return MEMORY_E;
1198 }
1199 XMEMSET(cert, 0, sizeof(Pkcs7Cert));
1200 cert->der = derCert;
1201 cert->derSz = derCertSz;
1202 cert->next = NULL;
1203
1204 /* free existing cert list if existing */
1205 wc_PKCS7_FreeCertSet(pkcs7);
1206
1207 /* add cert to list */
1208 if (pkcs7->certList == NULL) {
1209 pkcs7->certList = cert;
1210 } else {
1211 lastCert = pkcs7->certList;
1212 while (lastCert->next != NULL) {
1213 lastCert = lastCert->next;
1214 }
1215 lastCert->next = cert;
1216 }
1217
1218 InitDecodedCert(dCert, derCert, derCertSz, pkcs7->heap);
1219#ifdef WC_ASN_UNKNOWN_EXT_CB
1220 if (pkcs7->unknownExtCallback != NULL)
1221 wc_SetUnknownExtCallback(dCert, pkcs7->unknownExtCallback);
1222#endif
1223 ret = ParseCert(dCert, CA_TYPE, NO_VERIFY, 0);
1224 if (ret < 0) {
1225 FreeDecodedCert(dCert);
1226 WC_FREE_VAR_EX(dCert, pkcs7->heap, DYNAMIC_TYPE_DCERT);
1227 return ret;
1228 }
1229
1230 /* verify extracted public key is valid before storing */
1231 ret = wc_PKCS7_CheckPublicKeyDer(pkcs7, (int)dCert->keyOID,
1232 dCert->publicKey, dCert->pubKeySize);
1233 if (ret != 0) {
1234 WOLFSSL_MSG("Invalid public key, check pkcs7->cert");
1235 FreeDecodedCert(dCert);
1236 WC_FREE_VAR_EX(dCert, pkcs7->heap, DYNAMIC_TYPE_DCERT);
1237 return ret;
1238 }
1239
1240 if (dCert->pubKeySize > (MAX_RSA_INT_SZ + MAX_RSA_E_SZ) ||
1241 dCert->serialSz > MAX_SN_SZ) {
1242 WOLFSSL_MSG("Invalid size in certificate");
1243 FreeDecodedCert(dCert);
1244 WC_FREE_VAR_EX(dCert, pkcs7->heap, DYNAMIC_TYPE_DCERT);
1245 return ASN_PARSE_E;
1246 }
1247
1248 XMEMCPY(pkcs7->publicKey, dCert->publicKey, dCert->pubKeySize);
1249 pkcs7->publicKeySz = dCert->pubKeySize;
1250 pkcs7->publicKeyOID = dCert->keyOID;
1251 /* Do not derive publicKeyOID from cert signatureOID: the cert's
1252 * signature is how the cert was signed by its issuer; the signer
1253 * chooses digestEncryptionAlgorithm (e.g. RSASSA-PSS vs PKCS#1 v1.5)
1254 * via API / pkcs7->publicKeyOID set by the application. */
1255 XMEMCPY(pkcs7->issuerHash, dCert->issuerHash, KEYID_SIZE);
1256 pkcs7->issuer = dCert->issuerRaw;
1257 pkcs7->issuerSz = (word32)dCert->issuerRawLen;
1258 XMEMCPY(pkcs7->issuerSn, dCert->serial, (word32)dCert->serialSz);
1259 pkcs7->issuerSnSz = (word32)dCert->serialSz;
1260 XMEMCPY(pkcs7->issuerSubjKeyId, dCert->extSubjKeyId, KEYID_SIZE);
1261
1262 /* default to IssuerAndSerialNumber for SignerIdentifier */
1263 pkcs7->sidType = CMS_ISSUER_AND_SERIAL_NUMBER;
1264
1265 /* free existing recipient list if existing */
1266 wc_PKCS7_FreeEncodedRecipientSet(pkcs7);
1267
1268 FreeDecodedCert(dCert);
1269
1270 WC_FREE_VAR_EX(dCert, pkcs7->heap, DYNAMIC_TYPE_DCERT);
1271 }
1272
1273 return ret;
1274}
1275
1276
1277/* Adds one DER-formatted certificate to the internal PKCS7/CMS certificate
1278 * list, to be added as part of the certificates CertificateSet. Currently
1279 * used in SignedData content type.
1280 *
1281 * Must be called after wc_PKCS7_Init() or wc_PKCS7_InitWithCert().
1282 *
1283 * Does not represent the recipient/signer certificate, only certificates that
1284 * are part of the certificate chain used to build and verify signer
1285 * certificates.
1286 *
1287 * This API does not currently validate certificates.
1288 *
1289 * Returns 0 on success, negative upon error */
1290int wc_PKCS7_AddCertificate(wc_PKCS7* pkcs7, byte* derCert, word32 derCertSz)
1291{
1292 Pkcs7Cert* cert;
1293
1294 if (pkcs7 == NULL || derCert == NULL || derCertSz == 0)
1295 return BAD_FUNC_ARG;
1296
1297 cert = (Pkcs7Cert*)XMALLOC(sizeof(Pkcs7Cert), pkcs7->heap,
1298 DYNAMIC_TYPE_PKCS7);
1299 if (cert == NULL)
1300 return MEMORY_E;
1301 XMEMSET(cert, 0, sizeof(Pkcs7Cert));
1302
1303 cert->der = derCert;
1304 cert->derSz = derCertSz;
1305
1306 if (pkcs7->certList == NULL) {
1307 pkcs7->certList = cert;
1308 } else {
1309 cert->next = pkcs7->certList;
1310 pkcs7->certList = cert;
1311 }
1312
1313 return 0;
1314}
1315
1316
1317/* free linked list of PKCS7DecodedAttrib structs */
1318static void wc_PKCS7_FreeDecodedAttrib(PKCS7DecodedAttrib* attrib, void* heap)
1319{
1320 PKCS7DecodedAttrib* current;
1321
1322 if (attrib == NULL) {
1323 return;
1324 }
1325
1326 current = attrib;
1327 while (current != NULL) {
1328 PKCS7DecodedAttrib* next = current->next;
1329 XFREE(current->oid, heap, DYNAMIC_TYPE_PKCS7);
1330 XFREE(current->value, heap, DYNAMIC_TYPE_PKCS7);
1331 XFREE(current, heap, DYNAMIC_TYPE_PKCS7);
1332 current = next;
1333 }
1334
1335 (void)heap;
1336}
1337
1338
1339/* return 0 on success */
1340static int wc_PKCS7_SignerInfoNew(wc_PKCS7* pkcs7)
1341{
1342 XFREE(pkcs7->signerInfo, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
1343 pkcs7->signerInfo = NULL;
1344
1345 pkcs7->signerInfo = (PKCS7SignerInfo*)XMALLOC(sizeof(PKCS7SignerInfo),
1346 pkcs7->heap, DYNAMIC_TYPE_PKCS7);
1347 if (pkcs7->signerInfo == NULL) {
1348 WOLFSSL_MSG("Unable to malloc memory for signer info");
1349 return MEMORY_E;
1350 }
1351 XMEMSET(pkcs7->signerInfo, 0, sizeof(PKCS7SignerInfo));
1352 return 0;
1353}
1354
1355
1356static void wc_PKCS7_SignerInfoFree(wc_PKCS7* pkcs7)
1357{
1358 if (pkcs7->signerInfo != NULL) {
1359 XFREE(pkcs7->signerInfo->sid, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
1360 pkcs7->signerInfo->sid = NULL;
1361 XFREE(pkcs7->signerInfo, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
1362 pkcs7->signerInfo = NULL;
1363 }
1364}
1365
1366
1367/* free's any current SID and sets it to "in"
1368 * returns 0 on success
1369 */
1370static int wc_PKCS7_SignerInfoSetSID(wc_PKCS7* pkcs7, byte* in, int inSz)
1371{
1372 if (pkcs7 == NULL || in == NULL || inSz < 0) {
1373 return BAD_FUNC_ARG;
1374 }
1375
1376 XFREE(pkcs7->signerInfo->sid, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
1377 pkcs7->signerInfo->sid = NULL;
1378 pkcs7->signerInfo->sid = (byte*)XMALLOC((word32)inSz, pkcs7->heap,
1379 DYNAMIC_TYPE_PKCS7);
1380 if (pkcs7->signerInfo->sid == NULL) {
1381 return MEMORY_E;
1382 }
1383 XMEMCPY(pkcs7->signerInfo->sid, in, (word32)inSz);
1384 pkcs7->signerInfo->sidSz = (word32)inSz;
1385 return 0;
1386}
1387
1388
1389/* releases any memory allocated by a PKCS7 initializer */
1390void wc_PKCS7_Free(wc_PKCS7* pkcs7)
1391{
1392 if (pkcs7 == NULL)
1393 return;
1394
1395#ifndef NO_PKCS7_STREAM
1396 wc_PKCS7_FreeStream(pkcs7);
1397#endif
1398
1399 wc_PKCS7_SignerInfoFree(pkcs7);
1400 wc_PKCS7_FreeDecodedAttrib(pkcs7->decodedAttrib, pkcs7->heap);
1401 pkcs7->decodedAttrib = NULL;
1402 wc_PKCS7_FreeCertSet(pkcs7);
1403
1404#ifdef ASN_BER_TO_DER
1405 XFREE(pkcs7->der, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
1406 pkcs7->der = NULL;
1407#endif
1408 XFREE(pkcs7->contentDynamic, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
1409 pkcs7->contentDynamic = NULL;
1410
1411 if (pkcs7->cek != NULL) {
1412 ForceZero(pkcs7->cek, pkcs7->cekSz);
1413 XFREE(pkcs7->cek, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
1414 pkcs7->cek = NULL;
1415 }
1416
1417 pkcs7->contentTypeSz = 0;
1418
1419 if (pkcs7->signature) {
1420 XFREE(pkcs7->signature, pkcs7->heap, DYNAMIC_TYPE_SIGNATURE);
1421 pkcs7->signature = NULL;
1422 pkcs7->signatureSz = 0;
1423 }
1424 if (pkcs7->plainDigest) {
1425 XFREE(pkcs7->plainDigest, pkcs7->heap, DYNAMIC_TYPE_DIGEST);
1426 pkcs7->plainDigest = NULL;
1427 pkcs7->plainDigestSz = 0;
1428 }
1429 if (pkcs7->pkcs7Digest) {
1430 XFREE(pkcs7->pkcs7Digest, pkcs7->heap, DYNAMIC_TYPE_DIGEST);
1431 pkcs7->pkcs7Digest = NULL;
1432 pkcs7->pkcs7DigestSz = 0;
1433 }
1434 if (pkcs7->cachedEncryptedContent != NULL) {
1435 XFREE(pkcs7->cachedEncryptedContent, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
1436 pkcs7->cachedEncryptedContent = NULL;
1437 pkcs7->cachedEncryptedContentSz = 0;
1438 }
1439
1440 if (pkcs7->customSKID) {
1441 XFREE(pkcs7->customSKID, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
1442 pkcs7->customSKID = NULL;
1443 pkcs7->customSKIDSz = 0;
1444 }
1445
1446 if (pkcs7->isDynamic) {
1447 pkcs7->isDynamic = 0;
1448 XFREE(pkcs7, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
1449 }
1450}
1451
1452
1453/* helper function for parsing through attributes and finding a specific one.
1454 * returns PKCS7DecodedAttrib pointer on success */
1455static PKCS7DecodedAttrib* findAttrib(wc_PKCS7* pkcs7, const byte* oid, word32 oidSz)
1456{
1457 PKCS7DecodedAttrib* list;
1458
1459 if (pkcs7 == NULL || oid == NULL) {
1460 return NULL;
1461 }
1462
1463 /* search attributes for pkiStatus */
1464 list = pkcs7->decodedAttrib;
1465 while (list != NULL) {
1466 word32 sz = oidSz;
1467 word32 idx = 0;
1468 int length = 0;
1469 byte tag;
1470
1471 if (GetASNTag(list->oid, &idx, &tag, list->oidSz) < 0) {
1472 return NULL;
1473 }
1474 if (tag != ASN_OBJECT_ID) {
1475 WOLFSSL_MSG("Bad attribute ASN1 syntax");
1476 return NULL;
1477 }
1478
1479 if (GetLength(list->oid, &idx, &length, list->oidSz) < 0) {
1480 WOLFSSL_MSG("Bad attribute length");
1481 return NULL;
1482 }
1483
1484 sz = (sz < (word32)length)? sz : (word32)length;
1485 if (XMEMCMP(oid, list->oid + idx, sz) == 0) {
1486 return list;
1487 }
1488 list = list->next;
1489 }
1490 return NULL;
1491}
1492
1493
1494/* Searches through decoded attributes and returns the value for the first one
1495 * matching the oid passed in. Note that this value includes the leading ASN1
1496 * syntax. So for a printable string of "3" this would be something like
1497 *
1498 * 0x13, 0x01, 0x33
1499 * ID SIZE "3"
1500 *
1501 * pkcs7 structure to get value from
1502 * oid OID value to search for with attributes
1503 * oidSz size of oid buffer
1504 * out buffer to hold result
1505 * outSz size of out buffer (if out is NULL this is set to needed size and
1506 LENGTH_ONLY_E is returned)
1507 *
1508 * returns size of value on success
1509 */
1510int wc_PKCS7_GetAttributeValue(wc_PKCS7* pkcs7, const byte* oid, word32 oidSz,
1511 byte* out, word32* outSz)
1512{
1513 PKCS7DecodedAttrib* attrib;
1514
1515 if (pkcs7 == NULL || oid == NULL || outSz == NULL) {
1516 return BAD_FUNC_ARG;
1517 }
1518
1519 attrib = findAttrib(pkcs7, oid, oidSz);
1520 if (attrib == NULL) {
1521 return ASN_PARSE_E;
1522 }
1523
1524 if (out == NULL) {
1525 *outSz = attrib->valueSz;
1526 return WC_NO_ERR_TRACE(LENGTH_ONLY_E);
1527 }
1528
1529 if (*outSz < attrib->valueSz) {
1530 return BUFFER_E;
1531 }
1532
1533 XMEMCPY(out, attrib->value, attrib->valueSz);
1534 return (int)attrib->valueSz;
1535}
1536
1537
1538/* build PKCS#7 data content type */
1539int wc_PKCS7_EncodeData(wc_PKCS7* pkcs7, byte* output, word32 outputSz)
1540{
1541 static const byte oid[] =
1542 { ASN_OBJECT_ID, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01,
1543 0x07, 0x01 };
1544 byte seq[MAX_SEQ_SZ];
1545 byte octetStr[MAX_OCTET_STR_SZ];
1546 word32 seqSz;
1547 word32 octetStrSz;
1548 word32 oidSz = (word32)sizeof(oid);
1549 word32 idx = 0;
1550
1551 if (pkcs7 == NULL || output == NULL) {
1552 return BAD_FUNC_ARG;
1553 }
1554
1555 octetStrSz = SetOctetString(pkcs7->contentSz, octetStr);
1556 seqSz = SetSequence(pkcs7->contentSz + octetStrSz + oidSz, seq);
1557
1558 if (outputSz < pkcs7->contentSz + octetStrSz + oidSz + seqSz)
1559 return BUFFER_E;
1560
1561 XMEMCPY(output, seq, seqSz);
1562 idx += seqSz;
1563 XMEMCPY(output + idx, oid, oidSz);
1564 idx += oidSz;
1565 XMEMCPY(output + idx, octetStr, octetStrSz);
1566 idx += octetStrSz;
1567 XMEMCPY(output + idx, pkcs7->content, pkcs7->contentSz);
1568 idx += pkcs7->contentSz;
1569
1570 return (int)idx;
1571}
1572
1573
1574typedef struct EncodedAttrib {
1575 byte valueSeq[MAX_SEQ_SZ];
1576 const byte* oid;
1577 byte valueSet[MAX_SET_SZ];
1578 const byte* value;
1579 word32 valueSeqSz, oidSz, idSz, valueSetSz, valueSz, totalSz;
1580} EncodedAttrib;
1581
1582
1583typedef struct ESD {
1584 wc_HashAlg hash;
1585 enum wc_HashType hashType;
1586 byte contentDigest[WC_MAX_DIGEST_SIZE + 2]; /* content only + ASN.1 heading */
1587 WC_BITFIELD contentDigestSet:1;
1588 byte contentAttribsDigest[WC_MAX_DIGEST_SIZE];
1589 byte encContentDigest[MAX_ENCRYPTED_KEY_SZ];
1590
1591 byte outerSeq[MAX_SEQ_SZ];
1592 byte outerContent[MAX_EXP_SZ];
1593 byte innerSeq[MAX_SEQ_SZ];
1594 byte version[MAX_VERSION_SZ];
1595 byte digAlgoIdSet[MAX_SET_SZ];
1596 byte singleDigAlgoId[MAX_ALGO_SZ];
1597
1598 byte contentInfoSeq[MAX_SEQ_SZ];
1599 byte innerContSeq[MAX_EXP_SZ];
1600 byte innerOctets[MAX_OCTET_STR_SZ];
1601
1602 byte certsSet[MAX_SET_SZ];
1603
1604 byte signerInfoSet[MAX_SET_SZ];
1605 byte signerInfoSeq[MAX_SEQ_SZ];
1606 byte signerVersion[MAX_VERSION_SZ];
1607 /* issuerAndSerialNumber ...*/
1608 byte issuerSnSeq[MAX_SEQ_SZ];
1609 byte issuerName[MAX_SEQ_SZ];
1610 byte issuerSn[MAX_SN_SZ];
1611 /* OR subjectKeyIdentifier */
1612 byte issuerSKIDSeq[MAX_SEQ_SZ];
1613 byte issuerSKID[MAX_OCTET_STR_SZ];
1614 byte signerDigAlgoId[MAX_ALGO_SZ];
1615#if defined(WC_RSA_PSS)
1616 byte digEncAlgoId[128]; /* RSASSA-PSS needs full params */
1617#else
1618 byte digEncAlgoId[MAX_ALGO_SZ];
1619#endif
1620 byte signedAttribSet[MAX_SET_SZ];
1621 EncodedAttrib signedAttribs[7];
1622 byte signerDigest[MAX_OCTET_STR_SZ];
1623 word32 innerOctetsSz, innerContSeqSz, contentInfoSeqSz;
1624 word32 outerSeqSz, outerContentSz, innerSeqSz, versionSz, digAlgoIdSetSz,
1625 singleDigAlgoIdSz, certsSetSz;
1626 word32 signerInfoSetSz, signerInfoSeqSz, signerVersionSz,
1627 issuerSnSeqSz, issuerNameSz, issuerSnSz, issuerSKIDSz,
1628 issuerSKIDSeqSz, signerDigAlgoIdSz, digEncAlgoIdSz, signerDigestSz;
1629 word32 encContentDigestSz, signedAttribsSz, signedAttribsCount,
1630 signedAttribSetSz;
1631} ESD;
1632
1633
1634static int EncodeAttributes(EncodedAttrib* ea, int eaSz,
1635 PKCS7Attrib* attribs, int attribsSz)
1636{
1637 int i;
1638 int maxSz = (int)min((word32)eaSz, (word32)attribsSz);
1639 int allAttribsSz = 0;
1640
1641 for (i = 0; i < maxSz; i++)
1642 {
1643 word32 attribSz = 0;
1644
1645 ea[i].value = attribs[i].value;
1646 ea[i].valueSz = attribs[i].valueSz;
1647 attribSz += ea[i].valueSz;
1648 ea[i].valueSetSz = SetSet(attribSz, ea[i].valueSet);
1649 attribSz += ea[i].valueSetSz;
1650 ea[i].oid = attribs[i].oid;
1651 ea[i].oidSz = attribs[i].oidSz;
1652 attribSz += ea[i].oidSz;
1653 ea[i].valueSeqSz = SetSequence(attribSz, ea[i].valueSeq);
1654 attribSz += ea[i].valueSeqSz;
1655 ea[i].totalSz = attribSz;
1656
1657 allAttribsSz += (int)attribSz;
1658 }
1659 return allAttribsSz;
1660}
1661
1662
1663typedef struct FlatAttrib {
1664 byte* data;
1665 word32 dataSz;
1666} FlatAttrib;
1667
1668/* Returns a pointer to FlatAttrib whose members are initialized to 0.
1669* Caller is expected to free.
1670*/
1671static FlatAttrib* NewAttrib(void* heap)
1672{
1673 FlatAttrib* fb = (FlatAttrib*) XMALLOC(sizeof(FlatAttrib), heap,
1674 DYNAMIC_TYPE_TMP_BUFFER);
1675 if (fb != NULL) {
1676 ForceZero(fb, sizeof(FlatAttrib));
1677 }
1678 (void)heap;
1679 return fb;
1680}
1681
1682/* Free FlatAttrib array and memory allocated to internal struct members */
1683static void FreeAttribArray(wc_PKCS7* pkcs7, FlatAttrib** arr, int rows)
1684{
1685 int i;
1686
1687 if (arr) {
1688 for (i = 0; i < rows; i++) {
1689 if (arr[i]) {
1690 if (arr[i]->data) {
1691 ForceZero(arr[i]->data, arr[i]->dataSz);
1692 XFREE(arr[i]->data, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
1693 }
1694 ForceZero(arr[i], sizeof(FlatAttrib));
1695 XFREE(arr[i], pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
1696 }
1697 }
1698 ForceZero(arr, (word32)rows);
1699 XFREE(arr, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
1700 }
1701 (void)pkcs7;
1702}
1703
1704
1705/* Sort FlatAttrib array in ascending order */
1706static int SortAttribArray(FlatAttrib** arr, int rows)
1707{
1708 int i, j;
1709 word32 minSz, minIdx;
1710 FlatAttrib* a = NULL;
1711 FlatAttrib* b = NULL;
1712 FlatAttrib* tmp = NULL;
1713
1714 if (arr == NULL) {
1715 return BAD_FUNC_ARG;
1716 }
1717
1718 for (i = 0; i < rows; i++) {
1719 a = arr[i];
1720 minSz = a->dataSz;
1721 minIdx = (word32)i;
1722 for (j = i+1; j < rows; j++) {
1723 b = arr[j];
1724 if (b->dataSz < minSz) {
1725 minSz = b->dataSz;
1726 minIdx = (word32)j;
1727 }
1728 }
1729 if (minSz < a->dataSz) {
1730 /* swap array positions */
1731 tmp = arr[i];
1732 arr[i] = arr[minIdx];
1733 arr[minIdx] = tmp;
1734 }
1735 }
1736
1737 return 0;
1738}
1739
1740
1741/* Build up array of FlatAttrib structs from EncodedAttrib ones. FlatAttrib
1742 * holds flattened DER encoding of each attribute */
1743static int FlattenEncodedAttribs(wc_PKCS7* pkcs7, FlatAttrib** derArr, int rows,
1744 EncodedAttrib* ea, int eaSz)
1745{
1746 int i;
1747 word32 idx, sz;
1748 byte* output = NULL;
1749 FlatAttrib* fa = NULL;
1750
1751 if (pkcs7 == NULL || derArr == NULL || ea == NULL) {
1752 WOLFSSL_MSG("Invalid arguments to FlattenEncodedAttribs");
1753 return BAD_FUNC_ARG;
1754 }
1755
1756 if (rows != eaSz) {
1757 WOLFSSL_MSG("DER array not large enough to hold attribute count");
1758 return BAD_FUNC_ARG;
1759 }
1760
1761 for (i = 0; i < eaSz; i++) {
1762 sz = ea[i].valueSeqSz + ea[i].oidSz + ea[i].valueSetSz + ea[i].valueSz;
1763
1764 output = (byte*)XMALLOC(sz, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
1765 if (output == NULL) {
1766 return MEMORY_E;
1767 }
1768
1769 idx = 0;
1770 XMEMCPY(output + idx, ea[i].valueSeq, ea[i].valueSeqSz);
1771 idx += ea[i].valueSeqSz;
1772 XMEMCPY(output + idx, ea[i].oid, ea[i].oidSz);
1773 idx += ea[i].oidSz;
1774 XMEMCPY(output + idx, ea[i].valueSet, ea[i].valueSetSz);
1775 idx += ea[i].valueSetSz;
1776 XMEMCPY(output + idx, ea[i].value, ea[i].valueSz);
1777
1778 fa = derArr[i];
1779 fa->data = output;
1780 fa->dataSz = sz;
1781 }
1782
1783 return 0;
1784}
1785
1786
1787/* Sort and Flatten EncodedAttrib attributes into output buffer */
1788static int FlattenAttributes(wc_PKCS7* pkcs7, byte* output, EncodedAttrib* ea,
1789 int eaSz)
1790{
1791 int i, ret;
1792 word32 idx;
1793 FlatAttrib** derArr = NULL;
1794 FlatAttrib* fa = NULL;
1795
1796 if (pkcs7 == NULL || output == NULL || ea == NULL) {
1797 return BAD_FUNC_ARG;
1798 }
1799
1800 /* create array of FlatAttrib struct pointers to hold DER attribs */
1801 derArr = (FlatAttrib**) XMALLOC((unsigned long)eaSz * sizeof(FlatAttrib*),
1802 pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
1803 if (derArr == NULL) {
1804 return MEMORY_E;
1805 }
1806 XMEMSET(derArr, 0, (unsigned long)eaSz * sizeof(FlatAttrib*));
1807
1808 for (i = 0; i < eaSz; i++) {
1809 derArr[i] = NewAttrib(pkcs7->heap);
1810 if (derArr[i] == NULL) {
1811 FreeAttribArray(pkcs7, derArr, eaSz);
1812 return MEMORY_E;
1813 }
1814 ForceZero(derArr[i], sizeof(FlatAttrib));
1815 }
1816
1817 /* flatten EncodedAttrib into DER byte arrays */
1818 ret = FlattenEncodedAttribs(pkcs7, derArr, eaSz, ea, eaSz);
1819 if (ret != 0) {
1820 FreeAttribArray(pkcs7, derArr, eaSz);
1821 return ret;
1822 }
1823
1824 /* SET OF DER signed attributes must be sorted in ascending order */
1825 ret = SortAttribArray(derArr, eaSz);
1826 if (ret != 0) {
1827 FreeAttribArray(pkcs7, derArr, eaSz);
1828 return ret;
1829 }
1830
1831 /* copy sorted DER attribute arrays into output buffer */
1832 idx = 0;
1833 for (i = 0; i < eaSz; i++) {
1834 fa = derArr[i];
1835 XMEMCPY(output + idx, fa->data, fa->dataSz);
1836 idx += fa->dataSz;
1837 }
1838
1839 FreeAttribArray(pkcs7, derArr, eaSz);
1840
1841 return 0;
1842}
1843
1844
1845#ifndef NO_RSA
1846
1847static int wc_PKCS7_ImportRSA(wc_PKCS7* pkcs7, RsaKey* privKey)
1848{
1849 int ret;
1850 word32 idx;
1851
1852 ret = wc_InitRsaKey_ex(privKey, pkcs7->heap, pkcs7->devId);
1853 if (ret == 0) {
1854 if (pkcs7->privateKey != NULL && pkcs7->privateKeySz > 0) {
1855 idx = 0;
1856 ret = wc_RsaPrivateKeyDecode(pkcs7->privateKey, &idx, privKey,
1857 pkcs7->privateKeySz);
1858 /* If not using old FIPS or CAVP selftest, or not using FAST,
1859 * or USER RSA, able to check RSA key. */
1860 if (ret == 0) {
1861 #ifdef WOLFSSL_RSA_KEY_CHECK
1862 /* verify imported private key is a valid key before using it */
1863 ret = wc_CheckRsaKey(privKey);
1864 if (ret != 0) {
1865 WOLFSSL_MSG("Invalid RSA private key, check "
1866 "pkcs7->privateKey");
1867 }
1868 #endif
1869 }
1870 #ifdef WOLF_CRYPTO_CB
1871 else if (ret == WC_NO_ERR_TRACE(ASN_PARSE_E) &&
1872 pkcs7->devId != INVALID_DEVID) {
1873 /* if using crypto callbacks, try public key decode */
1874 idx = 0;
1875 ret = wc_RsaPublicKeyDecode(pkcs7->privateKey, &idx, privKey,
1876 pkcs7->privateKeySz);
1877 }
1878 #endif
1879 }
1880 #ifdef HAVE_PKCS7_RSA_RAW_SIGN_CALLBACK
1881 else if (pkcs7->rsaSignRawDigestCb != NULL && pkcs7->publicKeySz > 0) {
1882 /* When using raw sign callback (e.g., HSM/secure element), private
1883 * key may not be available. Use public key from signer certificate
1884 * for signature size calculation. */
1885 idx = 0;
1886 ret = wc_RsaPublicKeyDecode(pkcs7->publicKey, &idx, privKey,
1887 pkcs7->publicKeySz);
1888 }
1889 #endif
1890 else if (pkcs7->devId == INVALID_DEVID) {
1891 ret = BAD_FUNC_ARG;
1892 }
1893 }
1894
1895 return ret;
1896}
1897
1898
1899/* returns size of signature put into out, negative on error */
1900static int wc_PKCS7_RsaSign(wc_PKCS7* pkcs7, byte* in, word32 inSz, ESD* esd)
1901{
1902 int ret;
1903 WC_DECLARE_VAR(privKey, RsaKey, 1, 0);
1904
1905 if (pkcs7 == NULL || pkcs7->rng == NULL || in == NULL || esd == NULL) {
1906 return BAD_FUNC_ARG;
1907 }
1908
1909 WC_ALLOC_VAR_EX(privKey, RsaKey, 1, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER,
1910 return MEMORY_E);
1911
1912 ret = wc_PKCS7_ImportRSA(pkcs7, privKey);
1913 if (ret == 0) {
1914 #ifdef WOLFSSL_ASYNC_CRYPT
1915 do {
1916 ret = wc_AsyncWait(ret, &privKey->asyncDev,
1917 WC_ASYNC_FLAG_CALL_AGAIN);
1918 if (ret >= 0)
1919 #endif
1920 {
1921 ret = wc_RsaSSL_Sign(in, inSz, esd->encContentDigest,
1922 sizeof(esd->encContentDigest),
1923 privKey, pkcs7->rng);
1924 }
1925 #ifdef WOLFSSL_ASYNC_CRYPT
1926 } while (ret == WC_NO_ERR_TRACE(WC_PENDING_E));
1927 #endif
1928 }
1929
1930 wc_FreeRsaKey(privKey);
1931 WC_FREE_VAR_EX(privKey, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
1932
1933 return ret;
1934}
1935
1936#endif /* NO_RSA */
1937
1938
1939#ifdef HAVE_ECC
1940
1941static int wc_PKCS7_ImportECC(wc_PKCS7* pkcs7, ecc_key* privKey)
1942{
1943 int ret;
1944 word32 idx;
1945
1946 ret = wc_ecc_init_ex(privKey, pkcs7->heap, pkcs7->devId);
1947 if (ret == 0) {
1948 if (pkcs7->privateKey != NULL && pkcs7->privateKeySz > 0) {
1949 idx = 0;
1950 ret = wc_EccPrivateKeyDecode(pkcs7->privateKey, &idx, privKey,
1951 pkcs7->privateKeySz);
1952 /* verify imported private key is a valid key before using it */
1953 if (ret == 0) {
1954 ret = wc_ecc_check_key(privKey);
1955 if (ret != 0) {
1956 WOLFSSL_MSG("Invalid ECC private key, check "
1957 "pkcs7->privateKey");
1958 }
1959 }
1960 #ifdef WOLF_CRYPTO_CB
1961 else if (ret == WC_NO_ERR_TRACE(ASN_PARSE_E) &&
1962 pkcs7->devId != INVALID_DEVID) {
1963 /* if using crypto callbacks, try public key decode */
1964 idx = 0;
1965 ret = wc_EccPublicKeyDecode(pkcs7->privateKey, &idx, privKey,
1966 pkcs7->privateKeySz);
1967 }
1968 #endif
1969 }
1970 #ifdef HAVE_PKCS7_ECC_RAW_SIGN_CALLBACK
1971 else if (pkcs7->eccSignRawDigestCb != NULL && pkcs7->publicKeySz > 0) {
1972 /* When using raw sign callback (e.g., HSM/secure element), private
1973 * key may not be available. Use public key from signer certificate
1974 * for signature size calculation. */
1975 idx = 0;
1976 ret = wc_EccPublicKeyDecode(pkcs7->publicKey, &idx, privKey,
1977 pkcs7->publicKeySz);
1978 }
1979 #endif
1980 else if (pkcs7->devId == INVALID_DEVID) {
1981 ret = BAD_FUNC_ARG;
1982 }
1983 }
1984
1985 return ret;
1986}
1987
1988
1989/* returns size of signature put into out, negative on error */
1990static int wc_PKCS7_EcdsaSign(wc_PKCS7* pkcs7, byte* in, word32 inSz, ESD* esd)
1991{
1992 int ret;
1993 word32 outSz;
1994 WC_DECLARE_VAR(privKey, ecc_key, 1, 0);
1995
1996 if (pkcs7 == NULL || pkcs7->rng == NULL || in == NULL || esd == NULL) {
1997 return BAD_FUNC_ARG;
1998 }
1999
2000 WC_ALLOC_VAR_EX(privKey, ecc_key, 1, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER,
2001 return MEMORY_E);
2002
2003 ret = wc_PKCS7_ImportECC(pkcs7, privKey);
2004 if (ret == 0) {
2005 outSz = sizeof(esd->encContentDigest);
2006 #ifdef WOLFSSL_ASYNC_CRYPT
2007 do {
2008 ret = wc_AsyncWait(ret, &privKey->asyncDev,
2009 WC_ASYNC_FLAG_CALL_AGAIN);
2010 if (ret >= 0)
2011 #endif
2012 {
2013 ret = wc_ecc_sign_hash(in, inSz, esd->encContentDigest,
2014 &outSz, pkcs7->rng, privKey);
2015 }
2016 #ifdef WOLFSSL_ASYNC_CRYPT
2017 } while (ret == WC_NO_ERR_TRACE(WC_PENDING_E));
2018 #endif
2019 if (ret == 0)
2020 ret = (int)outSz;
2021 }
2022
2023 wc_ecc_free(privKey);
2024 WC_FREE_VAR_EX(privKey, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
2025
2026 return ret;
2027}
2028
2029#endif /* HAVE_ECC */
2030
2031#if defined(WC_RSA_PSS) && !defined(NO_RSA)
2032/* Map hash type to MGF1 identifier; local copy so PKCS7 does not depend on
2033 * rsa.c when RSA is in a separate FIPS module (e.g. CAVP build). */
2034static int pkcs7_hash2mgf(enum wc_HashType hType)
2035{
2036 switch (hType) {
2037 case WC_HASH_TYPE_NONE:
2038 return WC_MGF1NONE;
2039 case WC_HASH_TYPE_SHA:
2040#ifndef NO_SHA
2041 return WC_MGF1SHA1;
2042#else
2043 break;
2044#endif
2045 case WC_HASH_TYPE_SHA224:
2046#ifdef WOLFSSL_SHA224
2047 return WC_MGF1SHA224;
2048#else
2049 break;
2050#endif
2051 case WC_HASH_TYPE_SHA256:
2052#ifndef NO_SHA256
2053 return WC_MGF1SHA256;
2054#else
2055 break;
2056#endif
2057 case WC_HASH_TYPE_SHA384:
2058#ifdef WOLFSSL_SHA384
2059 return WC_MGF1SHA384;
2060#else
2061 break;
2062#endif
2063 case WC_HASH_TYPE_SHA512:
2064#ifdef WOLFSSL_SHA512
2065 return WC_MGF1SHA512;
2066#else
2067 break;
2068#endif
2069 /* MGF1 only supports SHA-1 and SHA-2; other hashes fall through to WC_MGF1NONE */
2070 case WC_HASH_TYPE_MD2:
2071 case WC_HASH_TYPE_MD4:
2072 case WC_HASH_TYPE_MD5:
2073 case WC_HASH_TYPE_MD5_SHA:
2074 case WC_HASH_TYPE_SHA3_224:
2075 case WC_HASH_TYPE_SHA3_256:
2076 case WC_HASH_TYPE_SHA3_384:
2077 case WC_HASH_TYPE_SHA3_512:
2078 case WC_HASH_TYPE_BLAKE2B:
2079 case WC_HASH_TYPE_BLAKE2S:
2080 case WC_HASH_TYPE_SHA512_224:
2081 case WC_HASH_TYPE_SHA512_256:
2082 case WC_HASH_TYPE_SHAKE128:
2083 case WC_HASH_TYPE_SHAKE256:
2084 case WC_HASH_TYPE_SM3:
2085 default:
2086 break;
2087 }
2088 return WC_MGF1NONE;
2089}
2090
2091/* returns size of signature put into esd->encContentDigest, negative on error.
2092 * Signs the digest (contentAttribsDigest) with RSA-PSS padding, like ECDSA. */
2093static int wc_PKCS7_RsaPssSign(wc_PKCS7* pkcs7, byte* digest, word32 digestSz,
2094 ESD* esd)
2095{
2096 int ret;
2097 word32 outSz;
2098 WC_DECLARE_VAR(privKey, RsaKey, 1, 0);
2099
2100 if (pkcs7 == NULL || pkcs7->rng == NULL || digest == NULL || esd == NULL) {
2101 return BAD_FUNC_ARG;
2102 }
2103
2104 WC_ALLOC_VAR_EX(privKey, RsaKey, 1, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER,
2105 return MEMORY_E);
2106
2107 ret = wc_PKCS7_ImportRSA(pkcs7, privKey);
2108 if (ret == 0) {
2109 outSz = sizeof(esd->encContentDigest);
2110#ifdef WOLFSSL_ASYNC_CRYPT
2111 do {
2112 ret = wc_AsyncWait(ret, &privKey->asyncDev,
2113 WC_ASYNC_FLAG_CALL_AGAIN);
2114 if (ret >= 0)
2115#endif
2116 {
2117 /* Salt length policy: use hash digest length (RFC 4055 typical).
2118 * RFC 3447 allows arbitrary salt lengths, but hash-length is the
2119 * most interoperable choice and matches OpenSSL's default.
2120 * Must agree with the saltLen encoded in
2121 * SignerInfo.signatureAlgorithm params above. */
2122 int saltLen = wc_HashGetDigestSize(wc_OidGetHash(pkcs7->hashOID));
2123 if (saltLen < 0) {
2124 ret = saltLen;
2125 }
2126 else {
2127 ret = wc_RsaPSS_Sign_ex(digest, digestSz,
2128 esd->encContentDigest, outSz,
2129 esd->hashType, pkcs7_hash2mgf(esd->hashType),
2130 saltLen, privKey, pkcs7->rng);
2131 }
2132 }
2133#ifdef WOLFSSL_ASYNC_CRYPT
2134 } while (ret == WC_NO_ERR_TRACE(WC_PENDING_E));
2135#endif
2136 /* wc_RsaPSS_Sign_ex returns signature length on success */
2137 }
2138
2139 wc_FreeRsaKey(privKey);
2140 WC_FREE_VAR_EX(privKey, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
2141
2142 return ret;
2143}
2144#endif /* WC_RSA_PSS && !NO_RSA */
2145
2146/* returns encContentDigestSz based on the signature set to be used */
2147static int wc_PKCS7_GetSignSize(wc_PKCS7* pkcs7)
2148{
2149 int ret = 0;
2150
2151 switch (pkcs7->publicKeyOID) {
2152
2153 #ifndef NO_RSA
2154 case RSAk:
2155 #ifdef WC_RSA_PSS
2156 case RSAPSSk:
2157 #endif
2158 {
2159 #ifndef WOLFSSL_SMALL_STACK
2160 RsaKey privKey[1];
2161 #else
2162 RsaKey* privKey;
2163 privKey = (RsaKey*)XMALLOC(sizeof(RsaKey), pkcs7->heap,
2164 DYNAMIC_TYPE_TMP_BUFFER);
2165 if (privKey == NULL)
2166 return MEMORY_E;
2167 #endif
2168
2169 ret = wc_PKCS7_ImportRSA(pkcs7, privKey);
2170 if (ret == 0) {
2171 ret = wc_RsaEncryptSize(privKey);
2172 }
2173 wc_FreeRsaKey(privKey);
2174 WC_FREE_VAR_EX(privKey, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
2175 }
2176 break;
2177 #endif
2178
2179 #ifdef HAVE_ECC
2180 case ECDSAk:
2181 {
2182 #ifndef WOLFSSL_SMALL_STACK
2183 ecc_key privKey[1];
2184 #else
2185 ecc_key* privKey;
2186 privKey = (ecc_key*)XMALLOC(sizeof(ecc_key), pkcs7->heap,
2187 DYNAMIC_TYPE_TMP_BUFFER);
2188 if (privKey == NULL)
2189 return MEMORY_E;
2190 #endif
2191
2192 ret = wc_PKCS7_ImportECC(pkcs7, privKey);
2193 if (ret == 0) {
2194 ret = wc_ecc_sig_size(privKey);
2195 }
2196 wc_ecc_free(privKey);
2197 WC_FREE_VAR_EX(privKey, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
2198 }
2199 break;
2200 #endif
2201 }
2202
2203 return ret;
2204}
2205
2206
2207/* builds up SignedData signed attributes, including default ones.
2208 *
2209 * pkcs7 - pointer to initialized PKCS7 structure
2210 * esd - pointer to initialized ESD structure, used for output
2211 *
2212 * return 0 on success, negative on error */
2213static int wc_PKCS7_BuildSignedAttributes(wc_PKCS7* pkcs7, ESD* esd,
2214 const byte* contentType, word32 contentTypeSz,
2215 const byte* contentTypeOid, word32 contentTypeOidSz,
2216 const byte* messageDigestOid, word32 messageDigestOidSz,
2217 const byte* signingTimeOid, word32 signingTimeOidSz,
2218 byte* signingTime, word32 signingTimeSz)
2219{
2220 int hashSz;
2221#ifdef NO_ASN_TIME
2222 PKCS7Attrib cannedAttribs[2];
2223#else
2224 time_t tm;
2225 int timeSz;
2226 PKCS7Attrib cannedAttribs[3];
2227#endif
2228 word32 idx = 0;
2229 word32 atrIdx = 0;
2230
2231 if (pkcs7 == NULL || esd == NULL || contentType == NULL ||
2232 contentTypeOid == NULL || messageDigestOid == NULL ||
2233 signingTimeOid == NULL) {
2234 return BAD_FUNC_ARG;
2235 }
2236
2237 if (pkcs7->defaultSignedAttribs != WOLFSSL_NO_ATTRIBUTES) {
2238 hashSz = wc_HashGetDigestSize(esd->hashType);
2239 if (hashSz < 0)
2240 return hashSz;
2241
2242 #ifndef NO_ASN_TIME
2243 if (signingTime == NULL || signingTimeSz == 0)
2244 return BAD_FUNC_ARG;
2245
2246 tm = wc_Time(0);
2247 timeSz = GetAsnTimeString(&tm, signingTime, signingTimeSz);
2248 if (timeSz < 0)
2249 return timeSz;
2250 #endif
2251
2252 XMEMSET(&cannedAttribs[idx], 0, sizeof(cannedAttribs[idx]));
2253
2254 if ((pkcs7->defaultSignedAttribs & WOLFSSL_CONTENT_TYPE_ATTRIBUTE) ||
2255 pkcs7->defaultSignedAttribs == 0) {
2256 cannedAttribs[idx].oid = contentTypeOid;
2257 cannedAttribs[idx].oidSz = contentTypeOidSz;
2258 cannedAttribs[idx].value = contentType;
2259 cannedAttribs[idx].valueSz = contentTypeSz;
2260 idx++;
2261 }
2262
2263 #ifndef NO_ASN_TIME
2264 if ((pkcs7->defaultSignedAttribs & WOLFSSL_SIGNING_TIME_ATTRIBUTE) ||
2265 pkcs7->defaultSignedAttribs == 0) {
2266 cannedAttribs[idx].oid = signingTimeOid;
2267 cannedAttribs[idx].oidSz = signingTimeOidSz;
2268 cannedAttribs[idx].value = signingTime;
2269 cannedAttribs[idx].valueSz = (word32)timeSz;
2270 idx++;
2271 }
2272 #endif
2273
2274 if ((pkcs7->defaultSignedAttribs & WOLFSSL_MESSAGE_DIGEST_ATTRIBUTE) ||
2275 pkcs7->defaultSignedAttribs == 0) {
2276 cannedAttribs[idx].oid = messageDigestOid;
2277 cannedAttribs[idx].oidSz = messageDigestOidSz;
2278 cannedAttribs[idx].value = esd->contentDigest;
2279 cannedAttribs[idx].valueSz = (word32)hashSz + 2; /* ASN.1 heading */
2280 idx++;
2281 }
2282
2283 esd->signedAttribsCount += idx;
2284 esd->signedAttribsSz += (word32)EncodeAttributes(
2285 &esd->signedAttribs[atrIdx], (int)idx, cannedAttribs,
2286 (int)idx);
2287 atrIdx += idx;
2288 } else {
2289 esd->signedAttribsCount = 0;
2290 esd->signedAttribsSz = 0;
2291 }
2292
2293 /* add custom signed attributes if set */
2294 if (pkcs7->signedAttribsSz > 0 && pkcs7->signedAttribs != NULL) {
2295 word32 availableSpace = MAX_SIGNED_ATTRIBS_SZ - atrIdx;
2296
2297 if (pkcs7->signedAttribsSz > availableSpace)
2298 return BUFFER_E;
2299
2300 esd->signedAttribsCount += pkcs7->signedAttribsSz;
2301 esd->signedAttribsSz += (word32)EncodeAttributes(
2302 &esd->signedAttribs[atrIdx], (int)esd->signedAttribsCount,
2303 pkcs7->signedAttribs, (int)pkcs7->signedAttribsSz);
2304 }
2305
2306#ifdef NO_ASN_TIME
2307 (void)signingTimeOidSz;
2308 (void)signingTime;
2309 (void)signingTimeSz;
2310#endif
2311
2312 return 0;
2313}
2314
2315
2316/* gets correct encryption algo ID for SignedData, either CTC_<hash>wRSA or
2317 * CTC_<hash>wECDSA, from pkcs7->publicKeyOID and pkcs7->hashOID.
2318 *
2319 * pkcs7 - pointer to PKCS7 structure
2320 * digEncAlgoId - [OUT] output int to store correct algo ID in
2321 * digEncAlgoType - [OUT] output for algo ID type
2322 *
2323 * return 0 on success, negative on error */
2324static int wc_PKCS7_SignedDataGetEncAlgoId(wc_PKCS7* pkcs7, int* digEncAlgoId,
2325 int* digEncAlgoType)
2326{
2327 int algoId = 0;
2328 int algoType = 0;
2329
2330 if (pkcs7 == NULL || digEncAlgoId == NULL || digEncAlgoType == NULL)
2331 return BAD_FUNC_ARG;
2332
2333 if (pkcs7->publicKeyOID == RSAk) {
2334
2335 algoType = oidSigType;
2336
2337 switch (pkcs7->hashOID) {
2338 #ifndef NO_SHA
2339 case SHAh:
2340 algoId = CTC_SHAwRSA;
2341 break;
2342 #endif
2343 #ifdef WOLFSSL_SHA224
2344 case SHA224h:
2345 algoId = CTC_SHA224wRSA;
2346 break;
2347 #endif
2348 #ifndef NO_SHA256
2349 case SHA256h:
2350 algoId = CTC_SHA256wRSA;
2351 break;
2352 #endif
2353 #ifdef WOLFSSL_SHA384
2354 case SHA384h:
2355 algoId = CTC_SHA384wRSA;
2356 break;
2357 #endif
2358 #ifdef WOLFSSL_SHA512
2359 case SHA512h:
2360 algoId = CTC_SHA512wRSA;
2361 break;
2362 #endif
2363 #ifdef WOLFSSL_SHA3
2364 #ifndef WOLFSSL_NOSHA3_224
2365 case SHA3_224h:
2366 algoId = CTC_SHA3_224wRSA;
2367 break;
2368 #endif
2369 #ifndef WOLFSSL_NOSHA3_256
2370 case SHA3_256h:
2371 algoId = CTC_SHA3_256wRSA;
2372 break;
2373 #endif
2374 #ifndef WOLFSSL_NOSHA3_384
2375 case SHA3_384h:
2376 algoId = CTC_SHA3_384wRSA;
2377 break;
2378 #endif
2379 #ifndef WOLFSSL_NOSHA3_512
2380 case SHA3_512h:
2381 algoId = CTC_SHA3_512wRSA;
2382 break;
2383 #endif
2384 #endif
2385 }
2386
2387 }
2388#ifdef HAVE_ECC
2389 else if (pkcs7->publicKeyOID == ECDSAk) {
2390
2391 algoType = oidSigType;
2392
2393 switch (pkcs7->hashOID) {
2394 #ifndef NO_SHA
2395 case SHAh:
2396 algoId = CTC_SHAwECDSA;
2397 break;
2398 #endif
2399 #ifdef WOLFSSL_SHA224
2400 case SHA224h:
2401 algoId = CTC_SHA224wECDSA;
2402 break;
2403 #endif
2404 #ifndef NO_SHA256
2405 case SHA256h:
2406 algoId = CTC_SHA256wECDSA;
2407 break;
2408 #endif
2409 #ifdef WOLFSSL_SHA384
2410 case SHA384h:
2411 algoId = CTC_SHA384wECDSA;
2412 break;
2413 #endif
2414 #ifdef WOLFSSL_SHA512
2415 case SHA512h:
2416 algoId = CTC_SHA512wECDSA;
2417 break;
2418 #endif
2419 #ifdef WOLFSSL_SHA3
2420 #ifndef WOLFSSL_NOSHA3_224
2421 case SHA3_224h:
2422 algoId = CTC_SHA3_224wECDSA;
2423 break;
2424 #endif
2425 #ifndef WOLFSSL_NOSHA3_256
2426 case SHA3_256h:
2427 algoId = CTC_SHA3_256wECDSA;
2428 break;
2429 #endif
2430 #ifndef WOLFSSL_NOSHA3_384
2431 case SHA3_384h:
2432 algoId = CTC_SHA3_384wECDSA;
2433 break;
2434 #endif
2435 #ifndef WOLFSSL_NOSHA3_512
2436 case SHA3_512h:
2437 algoId = CTC_SHA3_512wECDSA;
2438 break;
2439 #endif
2440 #endif
2441 }
2442 }
2443#endif /* HAVE_ECC */
2444
2445#ifdef WC_RSA_PSS
2446 else if (pkcs7->publicKeyOID == RSAPSSk) {
2447 algoType = oidSigType;
2448 algoId = CTC_RSASSAPSS;
2449 /* Hash/MGF/salt conveyed via PSS params in AlgorithmIdentifier */
2450 }
2451#endif
2452#ifndef WC_RSA_PSS
2453 else if (pkcs7->publicKeyOID == RSAPSSk) {
2454 WOLFSSL_MSG("RSA-PSS requested but WC_RSA_PSS not compiled in");
2455 return NOT_COMPILED_IN;
2456 }
2457#endif
2458
2459 if (algoId == 0) {
2460 WOLFSSL_MSG("Invalid signature algorithm type");
2461 return BAD_FUNC_ARG;
2462 }
2463
2464 *digEncAlgoId = algoId;
2465 *digEncAlgoType = algoType;
2466
2467 return 0;
2468}
2469
2470
2471/* build SignedData DigestInfo for use with PKCS#7/RSA
2472 *
2473 * pkcs7 - pointer to initialized PKCS7 struct
2474 * flatSignedAttribs - flattened, signed attributes
2475 * flatSignedAttrbsSz - size of flatSignedAttribs, octets
2476 * esd - pointer to initialized ESD struct
2477 * digestInfo - [OUT] output array for DigestInfo
2478 * digestInfoSz - [IN/OUT] - input size of array, size of digestInfo
2479 *
2480 * return 0 on success, negative on error */
2481static int wc_PKCS7_BuildDigestInfo(wc_PKCS7* pkcs7, byte* flatSignedAttribs,
2482 word32 flatSignedAttribsSz, ESD* esd,
2483 byte* digestInfo, word32* digestInfoSz)
2484{
2485 int ret, digIdx = 0;
2486 byte digestInfoSeq[MAX_SEQ_SZ];
2487 byte digestStr[MAX_OCTET_STR_SZ];
2488 byte attribSet[MAX_SET_SZ];
2489 byte algoId[MAX_ALGO_SZ];
2490 word32 digestInfoSeqSz, digestStrSz, algoIdSz, dgstInfoSz, hashSz;
2491 word32 attribSetSz;
2492
2493 if (pkcs7 == NULL || esd == NULL || digestInfo == NULL ||
2494 digestInfoSz == NULL) {
2495 return BAD_FUNC_ARG;
2496 }
2497
2498 ret = wc_HashGetDigestSize(esd->hashType);
2499 if (ret < 0)
2500 return ret;
2501 hashSz = (word32)ret;
2502
2503 if (flatSignedAttribsSz != 0) {
2504
2505 if (flatSignedAttribs == NULL)
2506 return BAD_FUNC_ARG;
2507
2508 attribSetSz = SetSet(flatSignedAttribsSz, attribSet);
2509
2510 ret = wc_HashInit(&esd->hash, esd->hashType);
2511 if (ret < 0)
2512 return ret;
2513
2514 ret = wc_HashUpdate(&esd->hash, esd->hashType,
2515 attribSet, attribSetSz);
2516 if (ret == 0)
2517 ret = wc_HashUpdate(&esd->hash, esd->hashType,
2518 flatSignedAttribs, flatSignedAttribsSz);
2519 if (ret == 0)
2520 ret = wc_HashFinal(&esd->hash, esd->hashType,
2521 esd->contentAttribsDigest);
2522 wc_HashFree(&esd->hash, esd->hashType);
2523
2524 if (ret < 0)
2525 return ret;
2526
2527 } else {
2528 /* when no attrs, digest is contentDigest without tag and length */
2529 XMEMCPY(esd->contentAttribsDigest, esd->contentDigest + 2, hashSz);
2530 }
2531
2532 /* Set algoID, allow absent hash params */
2533 algoIdSz = SetAlgoIDEx(pkcs7->hashOID, algoId, oidHashType,
2534 0, pkcs7->hashParamsAbsent);
2535
2536 digestStrSz = SetOctetString(hashSz, digestStr);
2537 dgstInfoSz = algoIdSz + digestStrSz + hashSz;
2538 digestInfoSeqSz = SetSequence(dgstInfoSz, digestInfoSeq);
2539
2540 if (*digestInfoSz < (digestInfoSeqSz + dgstInfoSz)) {
2541 return BUFFER_E;
2542 }
2543
2544 XMEMCPY(digestInfo + digIdx, digestInfoSeq, digestInfoSeqSz);
2545 digIdx += (int)digestInfoSeqSz;
2546 XMEMCPY(digestInfo + digIdx, algoId, algoIdSz);
2547 digIdx += (int)algoIdSz;
2548 XMEMCPY(digestInfo + digIdx, digestStr, digestStrSz);
2549 digIdx += (int)digestStrSz;
2550 XMEMCPY(digestInfo + digIdx, esd->contentAttribsDigest, hashSz);
2551 digIdx += (int)hashSz;
2552
2553 *digestInfoSz = (word32)digIdx;
2554
2555 return 0;
2556}
2557
2558
2559/* build SignedData signature over DigestInfo or content digest
2560 *
2561 * pkcs7 - pointer to initialized PKCS7 struct
2562 * flatSignedAttribs - flattened, signed attributes
2563 * flatSignedAttribsSz - size of flatSignedAttribs, octets
2564 * esd - pointer to initialized ESD struct
2565 *
2566 * returns length of signature on success, negative on error */
2567static int wc_PKCS7_SignedDataBuildSignature(wc_PKCS7* pkcs7,
2568 byte* flatSignedAttribs,
2569 word32 flatSignedAttribsSz,
2570 ESD* esd)
2571{
2572 int ret = 0;
2573#if defined(HAVE_ECC) || \
2574 (defined(HAVE_PKCS7_RSA_RAW_SIGN_CALLBACK) && !defined(NO_RSA)) || \
2575 (defined(WC_RSA_PSS) && !defined(NO_RSA))
2576 int hashSz = 0;
2577#endif
2578#if defined(HAVE_PKCS7_RSA_RAW_SIGN_CALLBACK) && !defined(NO_RSA)
2579 int hashOID;
2580#endif
2581 word32 digestInfoSz = MAX_PKCS7_DIGEST_SZ;
2582 WC_DECLARE_VAR(digestInfo, byte, MAX_PKCS7_DIGEST_SZ, 0);
2583
2584 if (pkcs7 == NULL || esd == NULL)
2585 return BAD_FUNC_ARG;
2586
2587 WC_ALLOC_VAR_EX(digestInfo, byte, digestInfoSz, pkcs7->heap,
2588 DYNAMIC_TYPE_TMP_BUFFER, return MEMORY_E);
2589 XMEMSET(digestInfo, 0, digestInfoSz);
2590
2591 ret = wc_PKCS7_BuildDigestInfo(pkcs7, flatSignedAttribs,
2592 flatSignedAttribsSz, esd, digestInfo,
2593 &digestInfoSz);
2594 if (ret < 0) {
2595 WC_FREE_VAR_EX(digestInfo, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
2596 return ret;
2597 }
2598
2599#if defined(HAVE_ECC) || \
2600 (defined(HAVE_PKCS7_RSA_RAW_SIGN_CALLBACK) && !defined(NO_RSA)) || \
2601 (defined(WC_RSA_PSS) && !defined(NO_RSA))
2602 /* get digest size from hash type */
2603 hashSz = wc_HashGetDigestSize(esd->hashType);
2604 if (hashSz < 0) {
2605 WC_FREE_VAR_EX(digestInfo, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
2606 return hashSz;
2607 }
2608#endif
2609
2610 /* sign digestInfo */
2611 switch (pkcs7->publicKeyOID) {
2612
2613#ifndef NO_RSA
2614 case RSAk:
2615 #ifdef HAVE_PKCS7_RSA_RAW_SIGN_CALLBACK
2616 if (pkcs7->rsaSignRawDigestCb != NULL) {
2617 /* get hash OID */
2618 hashOID = wc_HashGetOID(esd->hashType);
2619
2620 /* user signing plain digest, build DigestInfo themselves */
2621 ret = pkcs7->rsaSignRawDigestCb(pkcs7,
2622 esd->contentAttribsDigest, hashSz,
2623 esd->encContentDigest, sizeof(esd->encContentDigest),
2624 pkcs7->privateKey, pkcs7->privateKeySz, pkcs7->devId,
2625 hashOID);
2626 break;
2627 }
2628 #endif
2629 ret = wc_PKCS7_RsaSign(pkcs7, digestInfo, digestInfoSz, esd);
2630 break;
2631#endif
2632
2633#ifdef HAVE_ECC
2634 case ECDSAk:
2635 #ifdef HAVE_PKCS7_ECC_RAW_SIGN_CALLBACK
2636 if (pkcs7->eccSignRawDigestCb != NULL) {
2637 /* get hash OID */
2638 int eccHashOID = wc_HashGetOID(esd->hashType);
2639 if (eccHashOID < 0) {
2640 ret = eccHashOID;
2641 break;
2642 }
2643
2644 /* user signing plain digest */
2645 ret = pkcs7->eccSignRawDigestCb(pkcs7,
2646 esd->contentAttribsDigest, hashSz,
2647 esd->encContentDigest, sizeof(esd->encContentDigest),
2648 pkcs7->privateKey, pkcs7->privateKeySz, pkcs7->devId,
2649 eccHashOID);
2650 /* validate return value doesn't exceed buffer size */
2651 if (ret > 0 && (word32)ret > sizeof(esd->encContentDigest)) {
2652 ret = BUFFER_E;
2653 }
2654 break;
2655 }
2656 #endif
2657 /* CMS with ECDSA does not sign DigestInfo structure
2658 * like PKCS#7 with RSA does */
2659 ret = wc_PKCS7_EcdsaSign(pkcs7, esd->contentAttribsDigest,
2660 (word32)hashSz, esd);
2661 break;
2662#endif
2663
2664#if defined(WC_RSA_PSS) && !defined(NO_RSA)
2665 case RSAPSSk:
2666 /* RSA-PSS signs the digest directly (no DigestInfo), like ECDSA */
2667 ret = wc_PKCS7_RsaPssSign(pkcs7, esd->contentAttribsDigest,
2668 (word32)hashSz, esd);
2669 break;
2670#endif
2671
2672 default:
2673 WOLFSSL_MSG("Unsupported public key type");
2674 ret = BAD_FUNC_ARG;
2675 }
2676
2677 WC_FREE_VAR_EX(digestInfo, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
2678
2679 if (ret >= 0) {
2680 esd->encContentDigestSz = (word32)ret;
2681 }
2682
2683 return ret;
2684}
2685
2686#ifndef BER_OCTET_LENGTH
2687 #define BER_OCTET_LENGTH 4096
2688#endif
2689
2690/**
2691 * This helper function encodes a chunk of content stream and writes it out.
2692 *
2693 * @param pkcs7 Pointer to a PKCS7 structure.
2694 * @param cipherType The type of cipher to use for encryption.
2695 * @param aes Optional pointer to an Aes structure for AES encryption.
2696 * @param encContentOut Buffer to hold the encrypted content.
2697 * @param contentData Buffer holding the content to be encrypted.
2698 * @param contentDataSz Size of the content to be encrypted.
2699 * @param out Buffer to hold the output data.
2700 * @param outIdx Pointer to an index into the output buffer.
2701 * @param esd Pointer to an ESD structure for digest calculation.
2702 * @return Returns 0 on success, and a negative value on failure.
2703 */
2704static int wc_PKCS7_EncodeContentStreamHelper(wc_PKCS7* pkcs7, int cipherType,
2705 Aes* aes, byte* encContentOut, byte* contentData, int contentDataSz,
2706 byte* out, word32* outIdx, ESD* esd)
2707{
2708 int ret = WC_NO_ERR_TRACE(BAD_FUNC_ARG);
2709 byte encContentOutOct[MAX_OCTET_STR_SZ];
2710 word32 encContentOutOctSz = 0;
2711
2712 switch (cipherType) {
2713 case WC_CIPHER_NONE:
2714 XMEMCPY(encContentOut, contentData, (word32)contentDataSz);
2715 if (esd && esd->contentDigestSet != 1) {
2716 ret = wc_HashUpdate(&esd->hash, esd->hashType,
2717 contentData, (word32)contentDataSz);
2718 }
2719 break;
2720
2721 #ifndef NO_AES
2722 case WC_CIPHER_AES_CBC:
2723 ret = wc_AesCbcEncrypt(aes, encContentOut,
2724 contentData, (word32)contentDataSz);
2725 break;
2726 #endif
2727
2728 #ifdef WOLFSSL_AESGCM_STREAM
2729 case WC_CIPHER_AES_GCM:
2730 ret = wc_AesGcmEncryptUpdate(aes, encContentOut,
2731 contentData, (word32)contentDataSz, NULL, 0);
2732 break;
2733 #endif
2734 }
2735
2736 #ifdef WOLFSSL_ASYNC_CRYPT
2737 /* async encrypt not available here, so block till done */
2738 if (ret == WC_NO_ERR_TRACE(WC_PENDING_E) &&
2739 cipherType != WC_CIPHER_NONE) {
2740 ret = wc_AsyncWait(ret, &aes->asyncDev, WC_ASYNC_FLAG_NONE);
2741 }
2742 #endif
2743
2744 if (ret == 0) {
2745 encContentOutOctSz = SetOctetString((word32)contentDataSz, encContentOutOct);
2746 wc_PKCS7_WriteOut(pkcs7, (out)? out + *outIdx: NULL,
2747 encContentOutOct, encContentOutOctSz);
2748 *outIdx += encContentOutOctSz;
2749 wc_PKCS7_WriteOut(pkcs7, (out)? out + *outIdx : NULL,
2750 encContentOut, (word32)contentDataSz);
2751 *outIdx += (word32)contentDataSz;
2752 }
2753
2754 return ret;
2755}
2756
2757
2758/* Used for encoding the content, potentially one octet chunk at a time if
2759 * in streaming mode with IO callbacks set.
2760 * Can handle the cipher types:
2761 * - WC_CIPHER_NONE, used for encoding signed bundle where no encryption is
2762 * done.
2763 * - WC_CIPHER_AES_CBC
2764 * - WC_CIPHER_AES_GCM, requires WOLFSSL_AESGCM_STREAM for streaming
2765 * encryption
2766 * If ESD is passed in then hash of the conentet is collected as processed.
2767 *
2768 * Returns 0 on success */
2769#ifndef NO_AES
2770static int wc_PKCS7_EncodeContentStream(wc_PKCS7* pkcs7, ESD* esd, Aes* aes,
2771 const byte* in, int inSz, byte* out, int cipherType)
2772#else
2773static int wc_PKCS7_EncodeContentStream(wc_PKCS7* pkcs7, ESD* esd, void* aes,
2774 const byte* in, int inSz, byte* out, int cipherType)
2775#endif
2776{
2777 int ret = 0;
2778 int devId = pkcs7->devId;
2779 void* heap = pkcs7->heap;
2780
2781 if (pkcs7->encodeStream) {
2782 int sz;
2783 word32 totalSz = 0;
2784 const byte* buf;
2785 byte* encContentOut;
2786 byte* contentData;
2787 word32 idx = 0, outIdx = 0;
2788 word32 padSz = 0;
2789
2790 if (cipherType != WC_CIPHER_NONE) {
2791 padSz = (word32)wc_PKCS7_GetPadSize(pkcs7->contentSz,
2792 (word32)wc_PKCS7_GetOIDBlockSize(pkcs7->encryptOID));
2793 }
2794
2795 if (cipherType == WC_CIPHER_NONE && esd && esd->contentDigestSet != 1) {
2796 /* calculate hash for content */
2797 ret = wc_HashInit(&esd->hash, esd->hashType);
2798 if (ret != 0) {
2799 return ret;
2800 }
2801 }
2802
2803 encContentOut = (byte *)XMALLOC(BER_OCTET_LENGTH + MAX_OCTET_STR_SZ,
2804 heap, DYNAMIC_TYPE_PKCS7);
2805 contentData = (byte *)XMALLOC(BER_OCTET_LENGTH + padSz,
2806 heap, DYNAMIC_TYPE_PKCS7);
2807
2808 if (encContentOut == NULL || contentData == NULL) {
2809 XFREE(encContentOut, heap, DYNAMIC_TYPE_PKCS7);
2810 XFREE(contentData, heap, DYNAMIC_TYPE_PKCS7);
2811 WOLFSSL_MSG("Memory allocation failed for content data");
2812 return MEMORY_E;
2813 }
2814
2815 /* keep pulling from content until empty */
2816 do {
2817 int contentDataRead = 0;
2818
2819 #ifdef ASN_BER_TO_DER
2820 if (pkcs7->getContentCb) {
2821 contentDataRead =
2822 pkcs7->getContentCb(pkcs7, (byte **)(wc_ptr_t)&buf,
2823 pkcs7->streamCtx);
2824
2825 if (buf == NULL) {
2826 WOLFSSL_MSG("Get content callback returned null "
2827 "buffer pointer");
2828 XFREE(encContentOut, heap, DYNAMIC_TYPE_PKCS7);
2829 XFREE(contentData, heap, DYNAMIC_TYPE_PKCS7);
2830 return BAD_FUNC_ARG;
2831 }
2832 }
2833 else
2834 #endif
2835 {
2836 int szLeft = BER_OCTET_LENGTH;
2837
2838 if (in == NULL) {
2839 XFREE(encContentOut, heap, DYNAMIC_TYPE_PKCS7);
2840 XFREE(contentData, heap, DYNAMIC_TYPE_PKCS7);
2841 return BAD_FUNC_ARG;
2842 }
2843
2844 if ((word32)szLeft + totalSz > (word32)inSz)
2845 szLeft = inSz - (int)totalSz;
2846
2847 contentDataRead = szLeft;
2848 buf = in + totalSz;
2849 }
2850
2851 if (contentDataRead <= 0) {
2852 /* no more data returned from callback */
2853 break;
2854 }
2855 totalSz += (word32)contentDataRead;
2856
2857 /* check and handle octet boundary */
2858 sz = contentDataRead;
2859 if ((int)idx + sz > BER_OCTET_LENGTH) {
2860 int amtWritten = 0;
2861
2862 /* loop over current buffer until it is empty */
2863 while (idx + (word32)sz > BER_OCTET_LENGTH) {
2864 sz = BER_OCTET_LENGTH;
2865 if (idx > 0) { /* account for previously stored data */
2866 sz = BER_OCTET_LENGTH - (int)idx;
2867 }
2868 contentDataRead -= sz;
2869
2870 XMEMCPY(contentData + idx, buf, (word32)sz);
2871 ret = wc_PKCS7_EncodeContentStreamHelper(pkcs7, cipherType,
2872 aes, encContentOut, contentData, BER_OCTET_LENGTH, out,
2873 &outIdx, esd);
2874 if (ret != 0) {
2875 XFREE(encContentOut, heap, DYNAMIC_TYPE_PKCS7);
2876 XFREE(contentData, heap, DYNAMIC_TYPE_PKCS7);
2877 return ret;
2878 }
2879 idx = 0; /* cleared out previously stored data */
2880 amtWritten += sz;
2881 sz = contentDataRead;
2882 }
2883
2884 /* copy over any remaining data */
2885 XMEMCPY(contentData, buf + amtWritten, (word32)contentDataRead);
2886 idx = (word32)contentDataRead;
2887 }
2888 else {
2889 /* was not on an octet boundary, copy full
2890 * amount over */
2891 XMEMCPY(contentData + idx, buf, (word32)sz);
2892 idx += (word32)sz;
2893 }
2894 } while (totalSz < pkcs7->contentSz);
2895
2896 /* add in padding to the end */
2897 if ((cipherType != WC_CIPHER_NONE) && (totalSz == pkcs7->contentSz)) {
2898 word32 i;
2899
2900 if (BER_OCTET_LENGTH < idx) {
2901 XFREE(encContentOut, heap, DYNAMIC_TYPE_PKCS7);
2902 XFREE(contentData, heap, DYNAMIC_TYPE_PKCS7);
2903 return BAD_FUNC_ARG;
2904 }
2905
2906 for (i = 0; i < padSz; i++) {
2907 contentData[idx + i] = (byte)padSz;
2908 }
2909 idx += (word32)padSz;
2910 }
2911
2912 /* encrypt and flush out remainder of content data */
2913 ret = wc_PKCS7_EncodeContentStreamHelper(pkcs7, cipherType, aes,
2914 encContentOut, contentData, (int)idx, out, &outIdx, esd);
2915 if (ret == 0) {
2916 if (cipherType == WC_CIPHER_NONE && esd &&
2917 esd->contentDigestSet != 1) {
2918 ret = wc_HashFinal(&esd->hash, esd->hashType,
2919 esd->contentDigest + 2);
2920 wc_HashFree(&esd->hash, esd->hashType);
2921 }
2922 }
2923
2924 XFREE(encContentOut, heap, DYNAMIC_TYPE_PKCS7);
2925 XFREE(contentData, heap, DYNAMIC_TYPE_PKCS7);
2926 }
2927 else {
2928 if (in == NULL || out == NULL) {
2929 return BAD_FUNC_ARG;
2930 }
2931
2932 switch (cipherType) {
2933 case WC_CIPHER_NONE:
2934 if (!pkcs7->detached) {
2935 XMEMCPY(out, in, (word32)inSz);
2936 }
2937 if (esd && esd->contentDigestSet != 1) {
2938 ret = wc_HashInit(&esd->hash, esd->hashType);
2939 if (ret == 0)
2940 ret = wc_HashUpdate(&esd->hash, esd->hashType, in,
2941 (word32)inSz);
2942 if (ret == 0)
2943 ret = wc_HashFinal(&esd->hash, esd->hashType,
2944 esd->contentDigest + 2);
2945 wc_HashFree(&esd->hash, esd->hashType);
2946 }
2947 break;
2948
2949 #ifndef NO_AES
2950 case WC_CIPHER_AES_CBC:
2951 ret = wc_AesCbcEncrypt(aes, out, in, (word32)inSz);
2952 break;
2953 #endif
2954
2955 #ifdef WOLFSSL_AESGCM_STREAM
2956 case WC_CIPHER_AES_GCM:
2957 ret = wc_AesGcmEncryptUpdate(aes, out, in, (word32)inSz, NULL, 0);
2958 break;
2959 #endif
2960 }
2961 #ifdef WOLFSSL_ASYNC_CRYPT
2962 /* async encrypt not available here, so block till done */
2963 if (cipherType != WC_CIPHER_NONE) {
2964 ret = wc_AsyncWait(ret, &aes->asyncDev, WC_ASYNC_FLAG_NONE);
2965 }
2966 #endif
2967 }
2968
2969 (void)devId;
2970 (void)heap;
2971
2972 return ret;
2973}
2974
2975
2976/* build PKCS#7 signedData content type */
2977/* To get the output size then set output = 0 and *outputSz = 0 */
2978static int PKCS7_EncodeSigned(wc_PKCS7* pkcs7,
2979 const byte* hashBuf, word32 hashSz, byte* output, word32* outputSz,
2980 byte* output2, word32* output2Sz)
2981{
2982 /* contentType OID (1.2.840.113549.1.9.3) */
2983 static const byte contentTypeOid[] =
2984 { ASN_OBJECT_ID, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xF7, 0x0d, 0x01,
2985 0x09, 0x03 };
2986
2987 /* messageDigest OID (1.2.840.113549.1.9.4) */
2988 static const byte messageDigestOid[] =
2989 { ASN_OBJECT_ID, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01,
2990 0x09, 0x04 };
2991
2992 /* signingTime OID () */
2993 static const byte signingTimeOid[] =
2994 { ASN_OBJECT_ID, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01,
2995 0x09, 0x05};
2996
2997 Pkcs7Cert* certPtr = NULL;
2998 word32 certSetSz = 0;
2999
3000 word32 signerInfoSz = 0;
3001 word32 totalSz, total2Sz;
3002 int idx = 0, ret = 0;
3003 int digEncAlgoId, digEncAlgoType;
3004 int keyIdSize;
3005 byte* flatSignedAttribs = NULL;
3006 word32 flatSignedAttribsSz = 0;
3007
3008 WC_DECLARE_VAR(esd, ESD, 1, 0);
3009#ifdef ASN_BER_TO_DER
3010 word32 streamSz = 0;
3011#endif
3012 WC_DECLARE_VAR(signedDataOid, byte, MAX_OID_SZ, 0);
3013 word32 signedDataOidSz;
3014
3015 byte signingTime[MAX_TIME_STRING_SZ];
3016
3017 if (pkcs7 == NULL || pkcs7->hashOID == 0 ||
3018 outputSz == NULL) {
3019 WOLFSSL_MSG("PKCS7 struct / outputSz null, or hashOID is 0");
3020 return BAD_FUNC_ARG;
3021 }
3022
3023 if (hashSz == 0 && hashBuf != NULL) {
3024 return BAD_FUNC_ARG;
3025 }
3026
3027 /* signature size varies with ECDSA; RSA-PSS signs digest directly like
3028 * ECDSA. For both, content hash must be known to build ASN.1 before signing */
3029#if defined(HAVE_ECC) || defined(WC_RSA_PSS)
3030 if (hashBuf == NULL &&
3031 (pkcs7->publicKeyOID == ECDSAk
3032#ifdef WC_RSA_PSS
3033 || pkcs7->publicKeyOID == RSAPSSk
3034#endif
3035 )) {
3036 WOLFSSL_MSG("Pre-calculated content hash is needed in this case");
3037 return BAD_FUNC_ARG;
3038 }
3039#endif
3040
3041#if defined(WOLFSSL_SM2) && defined(WOLFSSL_SM3)
3042 keyIdSize = wc_HashGetDigestSize(wc_HashTypeConvert(HashIdAlg(
3043 pkcs7->publicKeyOID)));
3044#else
3045 keyIdSize = KEYID_SIZE;
3046#endif
3047
3048 /* use custom SKID if set */
3049 if (pkcs7->customSKIDSz > 0) {
3050 if (pkcs7->customSKID == NULL) {
3051 WOLFSSL_MSG("Bad custom SKID setup, size > 0 and was NULL");
3052 return BAD_FUNC_ARG;
3053 }
3054 keyIdSize = pkcs7->customSKIDSz;
3055 }
3056
3057#ifdef WOLFSSL_SMALL_STACK
3058 signedDataOid = (byte *)XMALLOC(MAX_OID_SZ, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
3059 if (signedDataOid == NULL) {
3060 idx = MEMORY_E;
3061 goto out;
3062 }
3063
3064 esd = (ESD*)XMALLOC(sizeof(ESD), pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
3065 if (esd == NULL) {
3066 idx = MEMORY_E;
3067 goto out;
3068 }
3069#endif
3070
3071 XMEMSET(esd, 0, sizeof(ESD));
3072
3073 /* set content type based on contentOID, unless user has set custom one
3074 with wc_PKCS7_SetContentType() */
3075 if (pkcs7->contentTypeSz == 0) {
3076
3077 /* default to DATA content type if user has not set */
3078 if (pkcs7->contentOID == 0) {
3079 pkcs7->contentOID = DATA;
3080 }
3081
3082 ret = wc_SetContentType(pkcs7->contentOID, pkcs7->contentType,
3083 sizeof(pkcs7->contentType));
3084 if (ret < 0) {
3085 idx = ret;
3086 goto out;
3087 }
3088 pkcs7->contentTypeSz = (word32)ret;
3089 }
3090
3091 /* set signedData outer content type */
3092 ret = wc_SetContentType(SIGNED_DATA, signedDataOid, MAX_OID_SZ);
3093 if (ret < 0) {
3094 idx = ret;
3095 goto out;
3096 }
3097 signedDataOidSz = (word32)ret;
3098
3099 if (pkcs7->sidType != DEGENERATE_SID) {
3100 esd->hashType = wc_OidGetHash(pkcs7->hashOID);
3101 if (hashBuf != NULL &&
3102 wc_HashGetDigestSize(esd->hashType) != (int)hashSz) {
3103 WOLFSSL_MSG("hashSz did not match hashOID");
3104 idx = BUFFER_E;
3105 goto out;
3106 }
3107
3108 /* include hash if provided, otherwise create hash when processing
3109 * content data */
3110 esd->contentDigest[0] = ASN_OCTET_STRING;
3111 if (hashBuf != NULL) {
3112 esd->contentDigestSet = 1;
3113 esd->contentDigest[1] = (byte)hashSz;
3114 XMEMCPY(&esd->contentDigest[2], hashBuf, hashSz);
3115 }
3116 else {
3117 esd->contentDigest[1] = (byte)wc_HashGetDigestSize(esd->hashType);
3118 }
3119 }
3120
3121 if (pkcs7->detached == 1) {
3122 /* do not include content if generating detached signature */
3123 esd->innerOctetsSz = 0;
3124 esd->innerContSeqSz = 0;
3125 esd->contentInfoSeqSz = SetSequence(pkcs7->contentTypeSz,
3126 esd->contentInfoSeq);
3127 }
3128 else {
3129 esd->innerOctetsSz = SetOctetStringEx(pkcs7->contentSz, esd->innerOctets,
3130 pkcs7->encodeStream);
3131 esd->innerContSeqSz = SetExplicit(0, esd->innerOctetsSz +
3132 pkcs7->contentSz, esd->innerContSeq,
3133 pkcs7->encodeStream);
3134 esd->contentInfoSeqSz = SetSequenceEx(pkcs7->contentSz +
3135 esd->innerOctetsSz + pkcs7->contentTypeSz +
3136 esd->innerContSeqSz, esd->contentInfoSeq,
3137 pkcs7->encodeStream);
3138 }
3139
3140 /* SignerIdentifier */
3141 if (pkcs7->sidType == CMS_ISSUER_AND_SERIAL_NUMBER) {
3142 /* IssuerAndSerialNumber */
3143 ret = SetSerialNumber(pkcs7->issuerSn, pkcs7->issuerSnSz,
3144 esd->issuerSn, MAX_SN_SZ, MAX_SN_SZ);
3145 if (ret < 0) {
3146 idx = ret;
3147 goto out;
3148 }
3149 esd->issuerSnSz = (word32)ret;
3150 signerInfoSz += esd->issuerSnSz;
3151 esd->issuerNameSz = SetSequence(pkcs7->issuerSz, esd->issuerName);
3152 signerInfoSz += esd->issuerNameSz + pkcs7->issuerSz;
3153 esd->issuerSnSeqSz = SetSequence(signerInfoSz, esd->issuerSnSeq);
3154 signerInfoSz += esd->issuerSnSeqSz;
3155
3156 if (pkcs7->version == 3) {
3157 /* RFC 4108 version MUST be 3 for firmware package signer */
3158 esd->signerVersionSz = (word32)SetMyVersion(3, esd->signerVersion, 0);
3159 }
3160 else {
3161 /* version MUST be 1 otherwise*/
3162 esd->signerVersionSz = (word32)SetMyVersion(1, esd->signerVersion, 0);
3163 }
3164
3165 } else if (pkcs7->sidType == CMS_SKID) {
3166 /* SubjectKeyIdentifier */
3167 esd->issuerSKIDSz = SetOctetString((word32)keyIdSize, esd->issuerSKID);
3168 esd->issuerSKIDSeqSz = SetExplicit(0, esd->issuerSKIDSz +
3169 (word32)keyIdSize,
3170 esd->issuerSKIDSeq, 0);
3171 signerInfoSz += (esd->issuerSKIDSz + esd->issuerSKIDSeqSz +
3172 (word32)keyIdSize);
3173
3174 /* version MUST be 3 */
3175 esd->signerVersionSz = (word32)SetMyVersion(3, esd->signerVersion, 0);
3176 } else if (pkcs7->sidType == DEGENERATE_SID) {
3177 /* no signer info added */
3178 } else {
3179 idx = SKID_E;
3180 goto out;
3181 }
3182
3183 if (pkcs7->sidType != DEGENERATE_SID) {
3184 signerInfoSz += esd->signerVersionSz;
3185 esd->signerDigAlgoIdSz = SetAlgoIDEx(pkcs7->hashOID, esd->signerDigAlgoId,
3186 oidHashType, 0, pkcs7->hashParamsAbsent);
3187 signerInfoSz += esd->signerDigAlgoIdSz;
3188
3189 /* set signatureAlgorithm */
3190 ret = wc_PKCS7_SignedDataGetEncAlgoId(pkcs7, &digEncAlgoId,
3191 &digEncAlgoType);
3192 if (ret < 0) {
3193 idx = ret;
3194 goto out;
3195 }
3196#if !defined(NO_RSA) && defined(WC_RSA_PSS)
3197 if (digEncAlgoId == CTC_RSASSAPSS) {
3198 /* Salt length policy: always encode as hash digest length.
3199 * This is the common CMS/RFC 4055 profile and matches OpenSSL
3200 * defaults. The decoder (pssSaltLen) handles arbitrary values
3201 * from external blobs. A future pkcs7->pssSaltLen override for
3202 * encode could be added here if custom salt lengths are needed. */
3203 int saltLen = wc_HashGetDigestSize(wc_OidGetHash(pkcs7->hashOID));
3204 if (saltLen < 0) {
3205 idx = saltLen;
3206 goto out;
3207 }
3208 esd->digEncAlgoIdSz = wc_EncodeRsaPssAlgoId(pkcs7->hashOID,
3209 (int)(word32)saltLen, esd->digEncAlgoId,
3210 (word32)sizeof(esd->digEncAlgoId));
3211 if (esd->digEncAlgoIdSz == 0) {
3212 idx = ASN_PARSE_E;
3213 goto out;
3214 }
3215 } else
3216#endif
3217 {
3218 esd->digEncAlgoIdSz = SetAlgoIDEx(digEncAlgoId, esd->digEncAlgoId,
3219 digEncAlgoType, 0, pkcs7->hashParamsAbsent);
3220 }
3221 signerInfoSz += esd->digEncAlgoIdSz;
3222
3223 /* build up signed attributes, include contentType, signingTime, and
3224 messageDigest by default */
3225 ret = wc_PKCS7_BuildSignedAttributes(pkcs7, esd, pkcs7->contentType,
3226 pkcs7->contentTypeSz,
3227 contentTypeOid, sizeof(contentTypeOid),
3228 messageDigestOid, sizeof(messageDigestOid),
3229 signingTimeOid, sizeof(signingTimeOid),
3230 signingTime, sizeof(signingTime));
3231 if (ret < 0) {
3232 idx = ret;
3233 goto out;
3234 }
3235
3236 if (esd->signedAttribsSz > 0) {
3237 flatSignedAttribs = (byte*)XMALLOC(esd->signedAttribsSz, pkcs7->heap,
3238 DYNAMIC_TYPE_PKCS7);
3239 if (flatSignedAttribs == NULL) {
3240 idx = MEMORY_E;
3241 goto out;
3242 }
3243
3244 flatSignedAttribsSz = esd->signedAttribsSz;
3245
3246 FlattenAttributes(pkcs7, flatSignedAttribs, esd->signedAttribs,
3247 (int)esd->signedAttribsCount);
3248 esd->signedAttribSetSz = SetImplicit(ASN_SET, 0, esd->signedAttribsSz,
3249 esd->signedAttribSet, 0);
3250 } else {
3251 esd->signedAttribSetSz = 0;
3252 }
3253
3254 if (pkcs7->publicKeyOID != ECDSAk && hashBuf == NULL) {
3255 ret = wc_PKCS7_GetSignSize(pkcs7);
3256 esd->encContentDigestSz = (word32)ret;
3257 }
3258 else {
3259 ret = wc_PKCS7_SignedDataBuildSignature(pkcs7, flatSignedAttribs,
3260 flatSignedAttribsSz, esd);
3261 }
3262 if (ret < 0) {
3263 idx = ret;
3264 goto out;
3265 }
3266
3267 signerInfoSz += flatSignedAttribsSz + esd->signedAttribSetSz;
3268
3269 esd->signerDigestSz = SetOctetString(esd->encContentDigestSz,
3270 esd->signerDigest);
3271 signerInfoSz += esd->signerDigestSz + esd->encContentDigestSz;
3272
3273 esd->signerInfoSeqSz = SetSequence(signerInfoSz, esd->signerInfoSeq);
3274 signerInfoSz += esd->signerInfoSeqSz;
3275 }
3276 esd->signerInfoSetSz = SetSet(signerInfoSz, esd->signerInfoSet);
3277 signerInfoSz += esd->signerInfoSetSz;
3278
3279 /* certificates [0] IMPLICIT CertificateSet */
3280 /* get total certificates size */
3281 if (pkcs7->noCerts != 1) {
3282 certPtr = pkcs7->certList;
3283 while (certPtr != NULL) {
3284 certSetSz += certPtr->derSz;
3285 certPtr = certPtr->next;
3286 }
3287 }
3288 certPtr = NULL;
3289
3290 if (certSetSz > 0)
3291 esd->certsSetSz = SetImplicit(ASN_SET, 0, certSetSz, esd->certsSet, 0);
3292
3293 if (pkcs7->sidType != DEGENERATE_SID) {
3294 esd->singleDigAlgoIdSz = SetAlgoIDEx(pkcs7->hashOID, esd->singleDigAlgoId,
3295 oidHashType, 0, pkcs7->hashParamsAbsent);
3296 }
3297 esd->digAlgoIdSetSz = SetSet(esd->singleDigAlgoIdSz, esd->digAlgoIdSet);
3298
3299 if (pkcs7->version == 3) {
3300 /* RFC 4108 version MUST be 3 for firmware package signer */
3301 esd->versionSz = (word32)SetMyVersion(3, esd->version, 0);
3302 }
3303 else {
3304 esd->versionSz = (word32)SetMyVersion(1, esd->version, 0);
3305 }
3306
3307 totalSz = esd->versionSz + esd->singleDigAlgoIdSz + esd->digAlgoIdSetSz +
3308 esd->contentInfoSeqSz + pkcs7->contentTypeSz +
3309 esd->innerContSeqSz + esd->innerOctetsSz;
3310
3311#ifdef ASN_BER_TO_DER
3312 if (pkcs7->encodeStream) {
3313 word32 tmpIdx = 0;
3314 totalSz += (3 * ASN_INDEF_END_SZ) ; /* 00's for BER with inner content */
3315
3316 StreamOctetString(pkcs7->content, pkcs7->contentSz, NULL, &streamSz,
3317 &tmpIdx);
3318 totalSz += streamSz + (3 * ASN_INDEF_END_SZ);
3319 }
3320 else
3321#endif
3322 {
3323 totalSz += pkcs7->contentSz;
3324 }
3325 total2Sz = esd->certsSetSz + certSetSz + signerInfoSz;
3326
3327 if (pkcs7->detached) {
3328 totalSz -= pkcs7->contentSz;
3329 }
3330
3331 esd->innerSeqSz = SetSequenceEx(totalSz + total2Sz, esd->innerSeq,
3332 pkcs7->encodeStream);
3333 totalSz += esd->innerSeqSz;
3334 if (pkcs7->encodeStream) {
3335 totalSz += ASN_INDEF_END_SZ;
3336 }
3337
3338 esd->outerContentSz = SetExplicit(0, totalSz + total2Sz,
3339 esd->outerContent, pkcs7->encodeStream);
3340 totalSz += esd->outerContentSz + signedDataOidSz;
3341 if (pkcs7->encodeStream) {
3342 totalSz += ASN_INDEF_END_SZ;
3343 }
3344
3345 esd->outerSeqSz = SetSequenceEx(totalSz + total2Sz, esd->outerSeq,
3346 pkcs7->encodeStream);
3347 totalSz += esd->outerSeqSz;
3348 if (pkcs7->encodeStream) {
3349 totalSz += ASN_INDEF_END_SZ;
3350 }
3351
3352 /* if using header/footer, we are not returning the content */
3353 if (output2 && output2Sz) {
3354 if (total2Sz > *output2Sz) {
3355 if (*outputSz == 0 && *output2Sz == 0) {
3356 *outputSz = totalSz;
3357 *output2Sz = total2Sz;
3358 idx = 0;
3359 goto out;
3360 }
3361 idx = BUFFER_E;
3362 goto out;
3363 }
3364
3365 if (!pkcs7->detached) {
3366 totalSz -= pkcs7->contentSz;
3367 }
3368 }
3369 else {
3370 /* if using single output buffer include content and footer */
3371 totalSz += total2Sz;
3372 }
3373
3374 if (totalSz > *outputSz
3375 #ifdef ASN_BER_TO_DER
3376 && pkcs7->streamOutCb == NULL
3377 #endif
3378 ) {
3379 if (*outputSz == 0) {
3380 #ifdef HAVE_ECC
3381 if (pkcs7->publicKeyOID == ECDSAk) {
3382 totalSz += ECC_MAX_PAD_SZ; /* signatures size can vary */
3383 }
3384 #endif
3385 *outputSz = totalSz;
3386 idx = (int)totalSz;
3387 goto out;
3388 }
3389 idx = BUFFER_E;
3390 goto out;
3391 }
3392
3393#ifdef ASN_BER_TO_DER
3394 if (output == NULL && pkcs7->streamOutCb == NULL) {
3395#else
3396 if (output == NULL) {
3397#endif
3398 idx = BUFFER_E;
3399 goto out;
3400 }
3401
3402 idx = 0;
3403 wc_PKCS7_WriteOut(pkcs7, (output)? (output + idx) : NULL,
3404 esd->outerSeq, esd->outerSeqSz);
3405 idx += (int)esd->outerSeqSz;
3406 wc_PKCS7_WriteOut(pkcs7, (output)? (output + idx) : NULL,
3407 signedDataOid, signedDataOidSz);
3408 idx += (int)signedDataOidSz;
3409 wc_PKCS7_WriteOut(pkcs7, (output)? (output + idx) : NULL,
3410 esd->outerContent, esd->outerContentSz);
3411 idx += (int)esd->outerContentSz;
3412 wc_PKCS7_WriteOut(pkcs7, (output)? (output + idx) : NULL,
3413 esd->innerSeq, esd->innerSeqSz);
3414 idx += (int)esd->innerSeqSz;
3415 wc_PKCS7_WriteOut(pkcs7, (output)? (output + idx) : NULL,
3416 esd->version, esd->versionSz);
3417 idx += (int)esd->versionSz;
3418 wc_PKCS7_WriteOut(pkcs7, (output)? (output + idx) : NULL,
3419 esd->digAlgoIdSet, esd->digAlgoIdSetSz);
3420 idx += (int)esd->digAlgoIdSetSz;
3421 wc_PKCS7_WriteOut(pkcs7, (output)? (output + idx) : NULL,
3422 esd->singleDigAlgoId, esd->singleDigAlgoIdSz);
3423 idx += (int)esd->singleDigAlgoIdSz;
3424 wc_PKCS7_WriteOut(pkcs7, (output)? (output + idx) : NULL,
3425 esd->contentInfoSeq, esd->contentInfoSeqSz);
3426 idx += (int)esd->contentInfoSeqSz;
3427 wc_PKCS7_WriteOut(pkcs7, (output)? (output + idx) : NULL,
3428 pkcs7->contentType, pkcs7->contentTypeSz);
3429 idx += (int)pkcs7->contentTypeSz;
3430 wc_PKCS7_WriteOut(pkcs7, (output)? (output + idx) : NULL,
3431 esd->innerContSeq, esd->innerContSeqSz);
3432 idx += (int)esd->innerContSeqSz;
3433 wc_PKCS7_WriteOut(pkcs7, (output)? (output + idx) : NULL,
3434 esd->innerOctets, esd->innerOctetsSz);
3435 idx += (int)esd->innerOctetsSz;
3436
3437 /* support returning header and footer without content */
3438 if (output2 && output2Sz) {
3439 *outputSz = (word32)idx;
3440 idx = 0;
3441 }
3442 else {
3443 if (
3444 #ifdef ASN_BER_TO_DER
3445 (pkcs7->content != NULL || pkcs7->getContentCb != NULL)
3446 #else
3447 pkcs7->content != NULL
3448 #endif
3449 && pkcs7->contentSz > 0) {
3450 wc_PKCS7_EncodeContentStream(pkcs7, esd, NULL, pkcs7->content,
3451 (int)pkcs7->contentSz, (output)? output + idx : NULL,
3452 WC_CIPHER_NONE);
3453 if (!pkcs7->detached) {
3454 #ifdef ASN_BER_TO_DER
3455 if (pkcs7->encodeStream) {
3456 byte indefEnd[ASN_INDEF_END_SZ * 3];
3457 word32 localIdx = 0;
3458
3459 idx += (int)streamSz;
3460
3461 /* end of content octet string */
3462 localIdx += SetIndefEnd(indefEnd + localIdx);
3463
3464 /* end of inner content seq */
3465 localIdx += SetIndefEnd(indefEnd + localIdx);
3466
3467 /* end of inner content info seq */
3468 localIdx += SetIndefEnd(indefEnd + localIdx);
3469
3470 wc_PKCS7_WriteOut(pkcs7, (output)? (output + idx) : NULL,
3471 indefEnd, localIdx);
3472 idx += (int)localIdx;
3473 }
3474 else
3475 #endif
3476 {
3477 idx += (int)pkcs7->contentSz;
3478 }
3479 }
3480 }
3481 output2 = output;
3482 }
3483
3484 /* certificates */
3485 wc_PKCS7_WriteOut(pkcs7, (output2)? (output2 + idx) : NULL,
3486 esd->certsSet, esd->certsSetSz);
3487 idx += (int)esd->certsSetSz;
3488
3489 if (pkcs7->noCerts != 1) {
3490 certPtr = pkcs7->certList;
3491 while (certPtr != NULL) {
3492 wc_PKCS7_WriteOut(pkcs7, (output2)? (output2 + idx) : NULL,
3493 certPtr->der, certPtr->derSz);
3494 idx += (int)certPtr->derSz;
3495 certPtr = certPtr->next;
3496 }
3497 }
3498
3499 wc_PKCS7_FreeCertSet(pkcs7);
3500
3501 wc_PKCS7_WriteOut(pkcs7, (output2)? (output2 + idx) : NULL,
3502 esd->signerInfoSet, esd->signerInfoSetSz);
3503 idx += (int)esd->signerInfoSetSz;
3504 wc_PKCS7_WriteOut(pkcs7, (output2)? (output2 + idx) : NULL,
3505 esd->signerInfoSeq, esd->signerInfoSeqSz);
3506 idx += (int)esd->signerInfoSeqSz;
3507 wc_PKCS7_WriteOut(pkcs7, (output2)? (output2 + idx) : NULL,
3508 esd->signerVersion, esd->signerVersionSz);
3509 idx += (int)esd->signerVersionSz;
3510 /* SignerIdentifier */
3511 if (pkcs7->sidType == CMS_ISSUER_AND_SERIAL_NUMBER) {
3512 /* IssuerAndSerialNumber */
3513 wc_PKCS7_WriteOut(pkcs7, (output2)? (output2 + idx) : NULL,
3514 esd->issuerSnSeq, esd->issuerSnSeqSz);
3515 idx += (int)esd->issuerSnSeqSz;
3516 wc_PKCS7_WriteOut(pkcs7, (output2)? (output2 + idx) : NULL,
3517 esd->issuerName, esd->issuerNameSz);
3518 idx += (int)esd->issuerNameSz;
3519 wc_PKCS7_WriteOut(pkcs7, (output2)? (output2 + idx) : NULL,
3520 pkcs7->issuer, pkcs7->issuerSz);
3521 idx += (int)pkcs7->issuerSz;
3522 wc_PKCS7_WriteOut(pkcs7, (output2)? (output2 + idx) : NULL,
3523 esd->issuerSn, esd->issuerSnSz);
3524 idx += (int)esd->issuerSnSz;
3525 } else if (pkcs7->sidType == CMS_SKID) {
3526 /* SubjectKeyIdentifier */
3527 wc_PKCS7_WriteOut(pkcs7, (output2)? (output2 + idx) : NULL,
3528 esd->issuerSKIDSeq, esd->issuerSKIDSeqSz);
3529 idx += (int)esd->issuerSKIDSeqSz;
3530 wc_PKCS7_WriteOut(pkcs7, (output2)? (output2 + idx) : NULL,
3531 esd->issuerSKID, esd->issuerSKIDSz);
3532 idx += (int)esd->issuerSKIDSz;
3533
3534 if (pkcs7->customSKID) {
3535 wc_PKCS7_WriteOut(pkcs7, (output2)? (output2 + idx) : NULL,
3536 pkcs7->customSKID, (word32)keyIdSize);
3537 }
3538 else {
3539 wc_PKCS7_WriteOut(pkcs7, (output2)? (output2 + idx) : NULL,
3540 pkcs7->issuerSubjKeyId, (word32)keyIdSize);
3541 }
3542 idx += keyIdSize;
3543 } else if (pkcs7->sidType == DEGENERATE_SID) {
3544 /* no signer infos in degenerate case */
3545 } else {
3546 idx = SKID_E;
3547 goto out;
3548 }
3549 wc_PKCS7_WriteOut(pkcs7, (output2)? (output2 + idx) : NULL,
3550 esd->signerDigAlgoId, esd->signerDigAlgoIdSz);
3551 idx += (int)esd->signerDigAlgoIdSz;
3552
3553 /* SignerInfo:Attributes */
3554 if (flatSignedAttribsSz > 0) {
3555 /* if the original hash buffer passed in was null then recreate the
3556 * signature */
3557 if (hashBuf == NULL && pkcs7->sidType != DEGENERATE_SID) {
3558 /* recreate flat attribs after the content hash is known if needed
3559 * build up signed attributes, include contentType, signingTime, and
3560 messageDigest by default */
3561 esd->signedAttribsCount = 0;
3562 esd->signedAttribsSz = 0;
3563 ret = wc_PKCS7_BuildSignedAttributes(pkcs7, esd, pkcs7->contentType,
3564 pkcs7->contentTypeSz,
3565 contentTypeOid, sizeof(contentTypeOid),
3566 messageDigestOid, sizeof(messageDigestOid),
3567 signingTimeOid, sizeof(signingTimeOid),
3568 signingTime, sizeof(signingTime));
3569 if (ret < 0) {
3570 idx = ret;
3571 goto out;
3572 }
3573
3574 if (esd->signedAttribsSz > 0) {
3575 if (flatSignedAttribs == NULL) {
3576 idx = MEMORY_E;
3577 goto out;
3578 }
3579
3580 flatSignedAttribsSz = esd->signedAttribsSz;
3581 FlattenAttributes(pkcs7, flatSignedAttribs,
3582 esd->signedAttribs,
3583 (int)esd->signedAttribsCount);
3584 } else {
3585 esd->signedAttribSetSz = 0;
3586 }
3587 }
3588
3589 wc_PKCS7_WriteOut(pkcs7, (output2)? (output2 + idx) : NULL,
3590 esd->signedAttribSet, esd->signedAttribSetSz);
3591 idx += (int)esd->signedAttribSetSz;
3592 wc_PKCS7_WriteOut(pkcs7, (output2)? (output2 + idx) : NULL,
3593 flatSignedAttribs, flatSignedAttribsSz);
3594 idx += (int)flatSignedAttribsSz;
3595 }
3596
3597 if (hashBuf == NULL && pkcs7->sidType != DEGENERATE_SID) {
3598 /* Calculate the final hash and encrypt it. */
3599 WOLFSSL_MSG("Recreating signature with new hash");
3600 ret = wc_PKCS7_SignedDataBuildSignature(pkcs7, flatSignedAttribs,
3601 flatSignedAttribsSz, esd);
3602 if (ret < 0) {
3603 idx = ret;
3604 goto out;
3605 }
3606 }
3607
3608 wc_PKCS7_WriteOut(pkcs7, (output2)? (output2 + idx) : NULL,
3609 esd->digEncAlgoId, esd->digEncAlgoIdSz);
3610 idx += (int)esd->digEncAlgoIdSz;
3611 wc_PKCS7_WriteOut(pkcs7, (output2)? (output2 + idx) : NULL,
3612 esd->signerDigest, esd->signerDigestSz);
3613 idx += (int)esd->signerDigestSz;
3614
3615 wc_PKCS7_WriteOut(pkcs7, (output2)? (output2 + idx) : NULL,
3616 esd->encContentDigest, esd->encContentDigestSz);
3617 idx += (int)esd->encContentDigestSz;
3618
3619#ifdef ASN_BER_TO_DER
3620 if (pkcs7->encodeStream) {
3621 byte indefEnd[ASN_INDEF_END_SZ * 3];
3622 word32 localIdx = 0;
3623
3624 /* end of signedData seq */
3625 localIdx += SetIndefEnd(indefEnd + localIdx);
3626
3627 /* end of outer content set */
3628 localIdx += SetIndefEnd(indefEnd + localIdx);
3629
3630 /* end of outer content info seq */
3631 localIdx += SetIndefEnd(indefEnd + localIdx);
3632
3633 wc_PKCS7_WriteOut(pkcs7, (output2)? (output2 + idx) : NULL,
3634 indefEnd, localIdx);
3635 idx += (int)localIdx;
3636 }
3637#endif
3638
3639 if (output2Sz) {
3640 *output2Sz = (word32)idx;
3641 idx = 0; /* success */
3642 }
3643 else {
3644 *outputSz = (word32)idx;
3645 }
3646
3647 out:
3648
3649 XFREE(flatSignedAttribs, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
3650
3651 WC_FREE_VAR_EX(esd, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
3652 WC_FREE_VAR_EX(signedDataOid, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
3653
3654 return idx;
3655}
3656
3657/* hashBuf: The computed digest for the pkcs7->content
3658 * hashSz: The size of computed digest for the pkcs7->content based on hashOID
3659 * outputHead: The PKCS7 header that goes on top of the raw data signed.
3660 * outputFoot: The PKCS7 footer that goes at the end of the raw data signed.
3661 * pkcs7->content: Not used
3662 * pkcs7->contentSz: Must be provided as actual sign of raw data
3663 * return codes: 0=success, negative=error
3664 */
3665int wc_PKCS7_EncodeSignedData_ex(wc_PKCS7* pkcs7, const byte* hashBuf,
3666 word32 hashSz, byte* outputHead, word32* outputHeadSz, byte* outputFoot,
3667 word32* outputFootSz)
3668{
3669 int ret;
3670
3671 /* other args checked in wc_PKCS7_EncodeSigned_ex */
3672 if (pkcs7 == NULL) {
3673 return BAD_FUNC_ARG;
3674 }
3675
3676#ifndef ASN_BER_TO_DER
3677 if (outputFoot == NULL || outputFootSz == NULL)
3678#else
3679 if (pkcs7->getContentCb == NULL &&
3680 (outputFoot == NULL || outputFootSz == NULL))
3681#endif
3682 {
3683 return BAD_FUNC_ARG;
3684 }
3685
3686 ret = PKCS7_EncodeSigned(pkcs7, hashBuf, hashSz,
3687 outputHead, outputHeadSz, outputFoot, outputFootSz);
3688
3689 return ret;
3690}
3691
3692
3693/* Sets a custom SKID in PKCS7 struct, used before calling an encode operation
3694 * Returns 0 on success, negative upon error. */
3695int wc_PKCS7_SetCustomSKID(wc_PKCS7* pkcs7, const byte* in, word16 inSz)
3696{
3697 int ret = 0;
3698
3699 if (pkcs7 == NULL || (in == NULL && inSz > 0)) {
3700 return BAD_FUNC_ARG;
3701 }
3702
3703 if (in == NULL) {
3704 if (pkcs7->customSKID != NULL) {
3705 XFREE(pkcs7->customSKID, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
3706 }
3707 pkcs7->customSKIDSz = 0;
3708 pkcs7->customSKID = NULL;
3709 }
3710 else {
3711 pkcs7->customSKID = (byte*)XMALLOC(inSz, pkcs7->heap,
3712 DYNAMIC_TYPE_PKCS7);
3713 if (pkcs7->customSKID == NULL) {
3714 ret = MEMORY_E;
3715 }
3716 else {
3717 XMEMCPY(pkcs7->customSKID, in, inSz);
3718 pkcs7->customSKIDSz = inSz;
3719 }
3720 }
3721
3722 return ret;
3723}
3724
3725
3726/* Toggle detached signature mode on/off for PKCS#7/CMS SignedData content type.
3727 * By default wolfCrypt includes the data to be signed in the SignedData
3728 * bundle. This data can be omitted in the case when a detached signature is
3729 * being created. To enable generation of detached signatures, set flag to "1",
3730 * otherwise set to "0":
3731 *
3732 * flag 1 turns on support
3733 * flag 0 turns off support
3734 *
3735 * pkcs7 - pointer to initialized PKCS7 structure
3736 * flag - turn on/off detached signature generation (1 or 0)
3737 *
3738 * Returns 0 on success, negative upon error. */
3739int wc_PKCS7_SetDetached(wc_PKCS7* pkcs7, word16 flag)
3740{
3741 if (pkcs7 == NULL || (flag != 0 && flag != 1))
3742 return BAD_FUNC_ARG;
3743
3744 pkcs7->detached = (flag != 0);
3745
3746 return 0;
3747}
3748
3749/* By default, SignedData bundles have the following signed attributes attached:
3750 * contentType (1.2.840.113549.1.9.3)
3751 * signingTime (1.2.840.113549.1.9.5)
3752 * messageDigest (1.2.840.113549.1.9.4)
3753 *
3754 * Calling this API before wc_PKCS7_EncodeSignedData() will disable the
3755 * inclusion of those attributes.
3756 *
3757 * pkcs7 - pointer to initialized PKCS7 structure
3758 *
3759 * Returns 0 on success, negative upon error. */
3760int wc_PKCS7_NoDefaultSignedAttribs(wc_PKCS7* pkcs7)
3761{
3762 return wc_PKCS7_SetDefaultSignedAttribs(pkcs7, WOLFSSL_NO_ATTRIBUTES);
3763}
3764
3765
3766/* By default, SignedData bundles have the following signed attributes attached:
3767 * contentType (1.2.840.113549.1.9.3)
3768 * signingTime (1.2.840.113549.1.9.5)
3769 * messageDigest (1.2.840.113549.1.9.4)
3770 *
3771 * Calling this API before wc_PKCS7_EncodeSignedData() allows control over which
3772 * default attributes are added.
3773 *
3774 * pkcs7 - pointer to initialized PKCS7 structure
3775 *
3776 * Returns 0 on success, negative upon error. */
3777int wc_PKCS7_SetDefaultSignedAttribs(wc_PKCS7* pkcs7, word16 flag)
3778{
3779 if (pkcs7 == NULL) {
3780 return BAD_FUNC_ARG;
3781 }
3782
3783 if (flag & WOLFSSL_NO_ATTRIBUTES) {
3784 if (flag ^ WOLFSSL_NO_ATTRIBUTES) {
3785 WOLFSSL_MSG("Error, can not have additional flags with no "
3786 "attributes flag set");
3787 return BAD_FUNC_ARG;
3788 }
3789 pkcs7->defaultSignedAttribs = 0;
3790 }
3791
3792 /* check for unknown flags */
3793 if (flag & ~(WOLFSSL_CONTENT_TYPE_ATTRIBUTE |
3794 WOLFSSL_SIGNING_TIME_ATTRIBUTE |
3795 WOLFSSL_MESSAGE_DIGEST_ATTRIBUTE | WOLFSSL_NO_ATTRIBUTES)) {
3796 WOLFSSL_MSG("Unknown attribute flags found");
3797 return BAD_FUNC_ARG;
3798 }
3799
3800 pkcs7->defaultSignedAttribs |= flag;
3801 return 0;
3802}
3803
3804
3805/* return codes: >0: Size of signed PKCS7 output buffer, negative: error */
3806int wc_PKCS7_EncodeSignedData(wc_PKCS7* pkcs7, byte* output, word32 outputSz)
3807{
3808 int ret;
3809
3810 /* other args checked in wc_PKCS7_EncodeSigned_ex */
3811 if (pkcs7 == NULL || (pkcs7->contentSz > 0 &&
3812 #ifdef ASN_BER_TO_DER
3813 (pkcs7->content == NULL && pkcs7->getContentCb == NULL))
3814 #else
3815 pkcs7->content == NULL)
3816 #endif
3817 ) {
3818 return BAD_FUNC_ARG;
3819 }
3820
3821 /* pre-calculate content hash for ECDSA and RSA-PSS (both sign digest directly) */
3822 if (pkcs7->publicKeyOID == ECDSAk
3823#ifdef WC_RSA_PSS
3824 || pkcs7->publicKeyOID == RSAPSSk
3825#endif
3826 ) {
3827 int hashSz;
3828 enum wc_HashType hashType;
3829 byte hashBuf[WC_MAX_DIGEST_SIZE];
3830 WC_DECLARE_VAR(hash, wc_HashAlg, 1, pkcs7->heap);
3831
3832 WC_ALLOC_VAR_EX(hash, wc_HashAlg, 1, pkcs7->heap, DYNAMIC_TYPE_HASHES,
3833 return MEMORY_E);
3834
3835 /* get hash type and size, validate hashOID */
3836 hashType = wc_OidGetHash(pkcs7->hashOID);
3837 hashSz = wc_HashGetDigestSize(hashType);
3838 if (hashSz < 0) {
3839 WC_FREE_VAR_EX(hash, pkcs7->heap, DYNAMIC_TYPE_HASHES);
3840 return hashSz;
3841 }
3842
3843 /* calculate hash for content */
3844 ret = wc_HashInit(hash, hashType);
3845 if (ret == 0) {
3846 ret = wc_HashUpdate(hash, hashType,
3847 pkcs7->content, pkcs7->contentSz);
3848 if (ret == 0) {
3849 ret = wc_HashFinal(hash, hashType, hashBuf);
3850 }
3851 wc_HashFree(hash, hashType);
3852 }
3853 WC_FREE_VAR_EX(hash, pkcs7->heap, DYNAMIC_TYPE_HASHES);
3854 if (ret == 0) {
3855 ret = PKCS7_EncodeSigned(pkcs7, hashBuf, (word32)hashSz,
3856 output, &outputSz, NULL, NULL);
3857 }
3858 }
3859 else {
3860 ret = PKCS7_EncodeSigned(pkcs7, NULL, 0, output, &outputSz,
3861 NULL, NULL);
3862 }
3863 return ret;
3864}
3865
3866
3867/* Single-shot API to generate a CMS SignedData bundle that encapsulates a
3868 * content of type FirmwarePkgData. Any recipient certificates should be
3869 * loaded into the PKCS7 structure prior to calling this function, using
3870 * wc_PKCS7_InitWithCert() and/or wc_PKCS7_AddCertificate().
3871 *
3872 * pkcs7 - pointer to initialized PKCS7 struct
3873 * privateKey - private RSA/ECC key, used for signing SignedData
3874 * privateKeySz - size of privateKey, octets
3875 * signOID - public key algorithm OID, used for sign operation
3876 * hashOID - hash algorithm OID, used for signature generation
3877 * content - content to be encapsulated, of type FirmwarePkgData
3878 * contentSz - size of content, octets
3879 * signedAttribs - optional signed attributes
3880 * signedAttribsSz - number of PKCS7Attrib members in signedAttribs
3881 * output - output buffer for final bundle
3882 * outputSz - size of output buffer, octets
3883 *
3884 * Returns length of generated bundle on success, negative upon error. */
3885int wc_PKCS7_EncodeSignedFPD(wc_PKCS7* pkcs7, byte* privateKey,
3886 word32 privateKeySz, int signOID, int hashOID,
3887 byte* content, word32 contentSz,
3888 PKCS7Attrib* signedAttribs, word32 signedAttribsSz,
3889 byte* output, word32 outputSz)
3890{
3891 int ret = 0;
3892 WC_RNG rng;
3893
3894 if (pkcs7 == NULL || privateKey == NULL || privateKeySz == 0 ||
3895 content == NULL || contentSz == 0 || output == NULL || outputSz == 0)
3896 return BAD_FUNC_ARG;
3897
3898 ret = wc_InitRng_ex(&rng, pkcs7->heap, pkcs7->devId);
3899 if (ret != 0)
3900 return ret;
3901
3902 pkcs7->rng = &rng;
3903 pkcs7->content = content;
3904 pkcs7->contentSz = contentSz;
3905 pkcs7->contentOID = FIRMWARE_PKG_DATA;
3906 pkcs7->hashOID = hashOID;
3907 pkcs7->encryptOID = signOID;
3908 pkcs7->privateKey = privateKey;
3909 pkcs7->privateKeySz = privateKeySz;
3910 pkcs7->signedAttribs = signedAttribs;
3911 pkcs7->signedAttribsSz = signedAttribsSz;
3912 pkcs7->version = 3;
3913
3914 ret = wc_PKCS7_EncodeSignedData(pkcs7, output, outputSz);
3915 if (ret <= 0) {
3916 WOLFSSL_MSG("Error encoding CMS SignedData content type");
3917 }
3918
3919 pkcs7->rng = NULL;
3920 wc_FreeRng(&rng);
3921
3922 return ret;
3923}
3924
3925#ifndef NO_PKCS7_ENCRYPTED_DATA
3926
3927/* Single-shot API to generate a CMS SignedData bundle that encapsulates a
3928 * CMS EncryptedData bundle. Content of inner EncryptedData is set to that
3929 * of FirmwarePkgData. Any recipient certificates should be loaded into the
3930 * PKCS7 structure prior to calling this function, using wc_PKCS7_InitWithCert()
3931 * and/or wc_PKCS7_AddCertificate().
3932 *
3933 * pkcs7 - pointer to initialized PKCS7 struct
3934 * encryptKey - encryption key used for encrypting EncryptedData
3935 * encryptKeySz - size of encryptKey, octets
3936 * privateKey - private RSA/ECC key, used for signing SignedData
3937 * privateKeySz - size of privateKey, octets
3938 * encryptOID - encryption algorithm OID, to be used as encryption
3939 * algorithm for EncryptedData
3940 * signOID - public key algorithm OID, to be used for sign
3941 * operation in SignedData generation
3942 * hashOID - hash algorithm OID, to be used for signature in
3943 * SignedData generation
3944 * content - content to be encapsulated
3945 * contentSz - size of content, octets
3946 * unprotectedAttribs - optional unprotected attributes, for EncryptedData
3947 * unprotectedAttribsSz - number of PKCS7Attrib members in unprotectedAttribs
3948 * signedAttribs - optional signed attributes, for SignedData
3949 * signedAttribsSz - number of PKCS7Attrib members in signedAttribs
3950 * output - output buffer for final bundle
3951 * outputSz - size of output buffer, octets
3952 *
3953 * Returns length of generated bundle on success, negative upon error. */
3954int wc_PKCS7_EncodeSignedEncryptedFPD(wc_PKCS7* pkcs7, byte* encryptKey,
3955 word32 encryptKeySz, byte* privateKey,
3956 word32 privateKeySz, int encryptOID,
3957 int signOID, int hashOID,
3958 byte* content, word32 contentSz,
3959 PKCS7Attrib* unprotectedAttribs,
3960 word32 unprotectedAttribsSz,
3961 PKCS7Attrib* signedAttribs,
3962 word32 signedAttribsSz,
3963 byte* output, word32 outputSz)
3964{
3965 int ret = 0, encryptedSz = 0;
3966 byte* encrypted = NULL;
3967 WC_RNG rng;
3968
3969 if (pkcs7 == NULL || encryptKey == NULL || encryptKeySz == 0 ||
3970 privateKey == NULL || privateKeySz == 0 || content == NULL ||
3971 contentSz == 0 || output == NULL || outputSz == 0) {
3972 return BAD_FUNC_ARG;
3973 }
3974
3975 /* 1: build up EncryptedData using FirmwarePkgData type, use output
3976 * buffer as tmp for storage and to get size */
3977
3978 /* set struct elements, inner content type is FirmwarePkgData */
3979 pkcs7->content = content;
3980 pkcs7->contentSz = contentSz;
3981 pkcs7->contentOID = FIRMWARE_PKG_DATA;
3982 pkcs7->encryptOID = encryptOID;
3983 pkcs7->encryptionKey = encryptKey;
3984 pkcs7->encryptionKeySz = encryptKeySz;
3985 pkcs7->unprotectedAttribs = unprotectedAttribs;
3986 pkcs7->unprotectedAttribsSz = unprotectedAttribsSz;
3987 pkcs7->version = 3;
3988
3989 encryptedSz = wc_PKCS7_EncodeEncryptedData(pkcs7, output, outputSz);
3990 if (encryptedSz < 0) {
3991 WOLFSSL_MSG("Error encoding CMS EncryptedData content type");
3992 return encryptedSz;
3993 }
3994
3995 /* save encryptedData, reset output buffer and struct */
3996 encrypted = (byte*)XMALLOC((word32)encryptedSz, pkcs7->heap,
3997 DYNAMIC_TYPE_PKCS7);
3998 if (encrypted == NULL) {
3999 ForceZero(output, outputSz);
4000 return MEMORY_E;
4001 }
4002
4003 XMEMCPY(encrypted, output, (word32)encryptedSz);
4004 ForceZero(output, outputSz);
4005
4006 ret = wc_InitRng_ex(&rng, pkcs7->heap, pkcs7->devId);
4007 if (ret != 0) {
4008 ForceZero(encrypted, (word32)encryptedSz);
4009 XFREE(encrypted, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
4010 return ret;
4011 }
4012
4013 /* 2: build up SignedData, encapsulating EncryptedData */
4014 pkcs7->rng = &rng;
4015 pkcs7->content = encrypted;
4016 pkcs7->contentSz = (word32)encryptedSz;
4017 pkcs7->contentOID = ENCRYPTED_DATA;
4018 pkcs7->hashOID = hashOID;
4019 pkcs7->encryptOID = signOID;
4020 pkcs7->privateKey = privateKey;
4021 pkcs7->privateKeySz = privateKeySz;
4022 pkcs7->signedAttribs = signedAttribs;
4023 pkcs7->signedAttribsSz = signedAttribsSz;
4024
4025 ret = wc_PKCS7_EncodeSignedData(pkcs7, output, outputSz);
4026 if (ret <= 0) {
4027 WOLFSSL_MSG("Error encoding CMS SignedData content type");
4028 }
4029
4030 ForceZero(encrypted, (word32)encryptedSz);
4031 XFREE(encrypted, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
4032 pkcs7->rng = NULL;
4033 wc_FreeRng(&rng);
4034
4035 return ret;
4036}
4037
4038#endif /* NO_PKCS7_ENCRYPTED_DATA */
4039
4040#if defined(HAVE_LIBZ) && !defined(NO_PKCS7_COMPRESSED_DATA)
4041/* Single-shot API to generate a CMS SignedData bundle that encapsulates a
4042 * CMS CompressedData bundle. Content of inner CompressedData is set to that
4043 * of FirmwarePkgData. Any recipient certificates should be loaded into the
4044 * PKCS7 structure prior to calling this function, using wc_PKCS7_InitWithCert()
4045 * and/or wc_PKCS7_AddCertificate().
4046 *
4047 * pkcs7 - pointer to initialized PKCS7 struct
4048 * privateKey - private RSA/ECC key, used for signing SignedData
4049 * privateKeySz - size of privateKey, octets
4050 * signOID - public key algorithm OID, to be used for sign
4051 * operation in SignedData generation
4052 * hashOID - hash algorithm OID, to be used for signature in
4053 * SignedData generation
4054 * content - content to be encapsulated
4055 * contentSz - size of content, octets
4056 * signedAttribs - optional signed attributes, for SignedData
4057 * signedAttribsSz - number of PKCS7Attrib members in signedAttribs
4058 * output - output buffer for final bundle
4059 * outputSz - size of output buffer, octets
4060 *
4061 * Returns length of generated bundle on success, negative upon error. */
4062int wc_PKCS7_EncodeSignedCompressedFPD(wc_PKCS7* pkcs7, byte* privateKey,
4063 word32 privateKeySz, int signOID,
4064 int hashOID, byte* content,
4065 word32 contentSz,
4066 PKCS7Attrib* signedAttribs,
4067 word32 signedAttribsSz, byte* output,
4068 word32 outputSz)
4069{
4070 int ret = 0, compressedSz = 0;
4071 byte* compressed = NULL;
4072 WC_RNG rng;
4073
4074 if (pkcs7 == NULL || privateKey == NULL || privateKeySz == 0 ||
4075 content == NULL || contentSz == 0 || output == NULL || outputSz == 0) {
4076 return BAD_FUNC_ARG;
4077 }
4078
4079 /* 1: build up CompressedData using FirmwarePkgData type, use output
4080 * buffer as tmp for storage and to get size */
4081
4082 /* set struct elements, inner content type is FirmwarePkgData */
4083 pkcs7->content = content;
4084 pkcs7->contentSz = contentSz;
4085 pkcs7->contentOID = FIRMWARE_PKG_DATA;
4086 pkcs7->version = 3;
4087
4088 compressedSz = wc_PKCS7_EncodeCompressedData(pkcs7, output, outputSz);
4089 if (compressedSz < 0) {
4090 WOLFSSL_MSG("Error encoding CMS CompressedData content type");
4091 return compressedSz;
4092 }
4093
4094 /* save compressedData, reset output buffer and struct */
4095 compressed = (byte*)XMALLOC(compressedSz, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
4096 if (compressed == NULL) {
4097 ForceZero(output, outputSz);
4098 return MEMORY_E;
4099 }
4100
4101 XMEMCPY(compressed, output, compressedSz);
4102 ForceZero(output, outputSz);
4103
4104 ret = wc_InitRng_ex(&rng, pkcs7->heap, pkcs7->devId);
4105 if (ret != 0) {
4106 ForceZero(compressed, compressedSz);
4107 XFREE(compressed, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
4108 return ret;
4109 }
4110
4111 /* 2: build up SignedData, encapsulating EncryptedData */
4112 pkcs7->rng = &rng;
4113 pkcs7->content = compressed;
4114 pkcs7->contentSz = compressedSz;
4115 pkcs7->contentOID = COMPRESSED_DATA;
4116 pkcs7->hashOID = hashOID;
4117 pkcs7->encryptOID = signOID;
4118 pkcs7->privateKey = privateKey;
4119 pkcs7->privateKeySz = privateKeySz;
4120 pkcs7->signedAttribs = signedAttribs;
4121 pkcs7->signedAttribsSz = signedAttribsSz;
4122
4123 ret = wc_PKCS7_EncodeSignedData(pkcs7, output, outputSz);
4124 if (ret <= 0) {
4125 WOLFSSL_MSG("Error encoding CMS SignedData content type");
4126 }
4127
4128 ForceZero(compressed, compressedSz);
4129 XFREE(compressed, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
4130 pkcs7->rng = NULL;
4131 wc_FreeRng(&rng);
4132
4133 return ret;
4134}
4135
4136#ifndef NO_PKCS7_ENCRYPTED_DATA
4137
4138/* Single-shot API to generate a CMS SignedData bundle that encapsulates a
4139 * CMS EncryptedData bundle, which then encapsulates a CMS CompressedData
4140 * bundle. Content of inner CompressedData is set to that of FirmwarePkgData.
4141 * Any recipient certificates should be loaded into the PKCS7 structure prior
4142 * to calling this function, using wc_PKCS7_InitWithCert() and/or
4143 * wc_PKCS7_AddCertificate().
4144 *
4145 * pkcs7 - pointer to initialized PKCS7 struct
4146 * encryptKey - encryption key used for encrypting EncryptedData
4147 * encryptKeySz - size of encryptKey, octets
4148 * privateKey - private RSA/ECC key, used for signing SignedData
4149 * privateKeySz - size of privateKey, octets
4150 * encryptOID - encryption algorithm OID, to be used as encryption
4151 * algorithm for EncryptedData
4152 * signOID - public key algorithm OID, to be used for sign
4153 * operation in SignedData generation
4154 * hashOID - hash algorithm OID, to be used for signature in
4155 * SignedData generation
4156 * content - content to be encapsulated
4157 * contentSz - size of content, octets
4158 * unprotectedAttribs - optional unprotected attributes, for EncryptedData
4159 * unprotectedAttribsSz - number of PKCS7Attrib members in unprotectedAttribs
4160 * signedAttribs - optional signed attributes, for SignedData
4161 * signedAttribsSz - number of PKCS7Attrib members in signedAttribs
4162 * output - output buffer for final bundle
4163 * outputSz - size of output buffer, octets
4164 *
4165 * Returns length of generated bundle on success, negative upon error. */
4166int wc_PKCS7_EncodeSignedEncryptedCompressedFPD(wc_PKCS7* pkcs7, byte* encryptKey,
4167 word32 encryptKeySz, byte* privateKey,
4168 word32 privateKeySz, int encryptOID,
4169 int signOID, int hashOID, byte* content,
4170 word32 contentSz,
4171 PKCS7Attrib* unprotectedAttribs,
4172 word32 unprotectedAttribsSz,
4173 PKCS7Attrib* signedAttribs,
4174 word32 signedAttribsSz,
4175 byte* output, word32 outputSz)
4176{
4177 int ret = 0, compressedSz = 0, encryptedSz = 0;
4178 byte* compressed = NULL;
4179 byte* encrypted = NULL;
4180 WC_RNG rng;
4181
4182 if (pkcs7 == NULL || encryptKey == NULL || encryptKeySz == 0 ||
4183 privateKey == NULL || privateKeySz == 0 || content == NULL ||
4184 contentSz == 0 || output == NULL || outputSz == 0) {
4185 return BAD_FUNC_ARG;
4186 }
4187
4188 /* 1: build up CompressedData using FirmwarePkgData type, use output
4189 * buffer as tmp for storage and to get size */
4190 pkcs7->content = content;
4191 pkcs7->contentSz = contentSz;
4192 pkcs7->contentOID = FIRMWARE_PKG_DATA;
4193 pkcs7->version = 3;
4194
4195 compressedSz = wc_PKCS7_EncodeCompressedData(pkcs7, output, outputSz);
4196 if (compressedSz < 0) {
4197 WOLFSSL_MSG("Error encoding CMS CompressedData content type");
4198 return compressedSz;
4199 }
4200
4201 /* save compressedData, reset output buffer and struct */
4202 compressed = (byte*)XMALLOC(compressedSz, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
4203 if (compressed == NULL)
4204 return MEMORY_E;
4205
4206 XMEMCPY(compressed, output, compressedSz);
4207 ForceZero(output, outputSz);
4208
4209 /* 2: build up EncryptedData using CompressedData, use output
4210 * buffer as tmp for storage and to get size */
4211 pkcs7->content = compressed;
4212 pkcs7->contentSz = compressedSz;
4213 pkcs7->contentOID = COMPRESSED_DATA;
4214 pkcs7->encryptOID = encryptOID;
4215 pkcs7->encryptionKey = encryptKey;
4216 pkcs7->encryptionKeySz = encryptKeySz;
4217 pkcs7->unprotectedAttribs = unprotectedAttribs;
4218 pkcs7->unprotectedAttribsSz = unprotectedAttribsSz;
4219
4220 encryptedSz = wc_PKCS7_EncodeEncryptedData(pkcs7, output, outputSz);
4221 if (encryptedSz < 0) {
4222 WOLFSSL_MSG("Error encoding CMS EncryptedData content type");
4223 XFREE(compressed, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
4224 return encryptedSz;
4225 }
4226
4227 /* save encryptedData, reset output buffer and struct */
4228 encrypted = (byte*)XMALLOC(encryptedSz, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
4229 if (encrypted == NULL) {
4230 ForceZero(compressed, compressedSz);
4231 XFREE(compressed, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
4232 return MEMORY_E;
4233 }
4234
4235 XMEMCPY(encrypted, output, encryptedSz);
4236 ForceZero(compressed, compressedSz);
4237 XFREE(compressed, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
4238 ForceZero(output, outputSz);
4239
4240 ret = wc_InitRng_ex(&rng, pkcs7->heap, pkcs7->devId);
4241 if (ret != 0) {
4242 ForceZero(encrypted, encryptedSz);
4243 XFREE(encrypted, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
4244 return ret;
4245 }
4246
4247 /* 3: build up SignedData, encapsulating EncryptedData */
4248 pkcs7->rng = &rng;
4249 pkcs7->content = encrypted;
4250 pkcs7->contentSz = encryptedSz;
4251 pkcs7->contentOID = ENCRYPTED_DATA;
4252 pkcs7->hashOID = hashOID;
4253 pkcs7->encryptOID = signOID;
4254 pkcs7->privateKey = privateKey;
4255 pkcs7->privateKeySz = privateKeySz;
4256 pkcs7->signedAttribs = signedAttribs;
4257 pkcs7->signedAttribsSz = signedAttribsSz;
4258
4259 ret = wc_PKCS7_EncodeSignedData(pkcs7, output, outputSz);
4260 if (ret <= 0) {
4261 WOLFSSL_MSG("Error encoding CMS SignedData content type");
4262 }
4263
4264 ForceZero(encrypted, encryptedSz);
4265 XFREE(encrypted, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
4266 pkcs7->rng = NULL;
4267 wc_FreeRng(&rng);
4268
4269 return ret;
4270}
4271
4272#endif /* !NO_PKCS7_ENCRYPTED_DATA */
4273#endif /* HAVE_LIBZ && !NO_PKCS7_COMPRESSED_DATA */
4274
4275
4276#ifndef NO_RSA
4277
4278#ifdef HAVE_PKCS7_RSA_RAW_SIGN_CALLBACK
4279/* register raw RSA sign digest callback */
4280int wc_PKCS7_SetRsaSignRawDigestCb(wc_PKCS7* pkcs7, CallbackRsaSignRawDigest cb)
4281{
4282 if (pkcs7 == NULL || cb == NULL) {
4283 return BAD_FUNC_ARG;
4284 }
4285
4286 pkcs7->rsaSignRawDigestCb = cb;
4287
4288 return 0;
4289}
4290#endif
4291
4292#endif /* NO_RSA */
4293
4294
4295#ifdef HAVE_ECC
4296
4297#ifdef HAVE_PKCS7_ECC_RAW_SIGN_CALLBACK
4298/* register raw ECC sign digest callback */
4299int wc_PKCS7_SetEccSignRawDigestCb(wc_PKCS7* pkcs7, CallbackEccSignRawDigest cb)
4300{
4301 if (pkcs7 == NULL || cb == NULL) {
4302 return BAD_FUNC_ARG;
4303 }
4304
4305 pkcs7->eccSignRawDigestCb = cb;
4306
4307 return 0;
4308}
4309#endif
4310
4311#endif /* HAVE_ECC */
4312
4313
4314#if !defined(NO_RSA) || defined(HAVE_ECC)
4315/* Check whether the given decoded certificate matches the SignerIdentifier
4316 * (sid) field of the currently parsed SignerInfo. Per RFC 5652 Section 5.3,
4317 * the sid selects which certificate's public key must be used to verify the
4318 * signature. Returns 1 on match, 0 on no match or when the sid is not
4319 * available for comparison. */
4320static int wc_PKCS7_CertMatchesSignerInfo(wc_PKCS7* pkcs7, DecodedCert* dCert)
4321{
4322 PKCS7SignerInfo* signerInfo;
4323
4324 if (pkcs7 == NULL || dCert == NULL)
4325 return 0;
4326
4327 signerInfo = pkcs7->signerInfo;
4328 if (signerInfo == NULL || signerInfo->sid == NULL ||
4329 signerInfo->sidSz == 0) {
4330 /* No SID parsed, cannot perform an identity binding check. */
4331 return 0;
4332 }
4333
4334 if (signerInfo->sidType == CMS_ISSUER_AND_SERIAL_NUMBER) {
4335 /* IssuerAndSerialNumber: SID blob stores the content of the outer
4336 * SEQUENCE (issuer Name followed by INTEGER serialNumber). */
4337 word32 idx = 0;
4338 byte sidIssuerHash[KEYID_SIZE];
4339 WC_DECLARE_VAR(sidSerial, mp_int, 1, pkcs7->heap);
4340 WC_DECLARE_VAR(certSerial, mp_int, 1, pkcs7->heap);
4341 int cmp;
4342 int match = 0;
4343
4344 if (GetNameHash_ex(signerInfo->sid, &idx, sidIssuerHash,
4345 (int)signerInfo->sidSz, dCert->signatureOID) < 0) {
4346 return 0;
4347 }
4348 if (XMEMCMP(sidIssuerHash, dCert->issuerHash, KEYID_SIZE) != 0)
4349 return 0;
4350
4351 WC_ALLOC_VAR_EX(sidSerial, mp_int, 1, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER,
4352 { return 0; });
4353 WC_ALLOC_VAR_EX(certSerial, mp_int, 1, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER,
4354 { WC_FREE_VAR_EX(sidSerial, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
4355 return 0; });
4356
4357 if (mp_init(sidSerial) != MP_OKAY) {
4358 WC_FREE_VAR_EX(sidSerial, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
4359 WC_FREE_VAR_EX(certSerial, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
4360 return 0;
4361 }
4362 if (mp_init(certSerial) != MP_OKAY) {
4363 mp_clear(sidSerial);
4364 WC_FREE_VAR_EX(sidSerial, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
4365 WC_FREE_VAR_EX(certSerial, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
4366 return 0;
4367 }
4368
4369 if (GetInt(sidSerial, signerInfo->sid, &idx, signerInfo->sidSz) == 0 &&
4370 mp_read_unsigned_bin(certSerial, dCert->serial,
4371 (word32)dCert->serialSz) == MP_OKAY) {
4372 cmp = mp_cmp(sidSerial, certSerial);
4373 if (cmp == MP_EQ)
4374 match = 1;
4375 }
4376
4377 mp_clear(sidSerial);
4378 mp_clear(certSerial);
4379 WC_FREE_VAR_EX(sidSerial, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
4380 WC_FREE_VAR_EX(certSerial, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
4381 return match;
4382 }
4383 else if (signerInfo->sidType == CMS_SKID) {
4384 /* SubjectKeyIdentifier: SID blob is the raw SKID octet string
4385 * content. Normalize the same way the certificate side does so
4386 * that comparisons between SHA-1 SKIDs and other lengths match. */
4387 byte sidKid[KEYID_SIZE];
4388
4389 if (GetHashId(signerInfo->sid, (int)signerInfo->sidSz, sidKid,
4390 HashIdAlg(dCert->signatureOID)) != 0) {
4391 return 0;
4392 }
4393 if (XMEMCMP(sidKid, dCert->extSubjKeyId, KEYID_SIZE) == 0)
4394 return 1;
4395 return 0;
4396 }
4397
4398 return 0;
4399}
4400#endif /* !NO_RSA || HAVE_ECC */
4401
4402#ifndef NO_RSA
4403
4404/* returns size of signature put into out, negative on error */
4405static int wc_PKCS7_RsaVerify(wc_PKCS7* pkcs7, byte* sig, int sigSz,
4406 byte* hash, word32 hashSz)
4407{
4408 int ret = 0, i;
4409 word32 scratch = 0, verified = 0;
4410#ifdef WOLFSSL_SMALL_STACK
4411 byte* digest;
4412 RsaKey* key;
4413 DecodedCert* dCert;
4414#else
4415#ifdef WOLFSSL_NO_MALLOC
4416 byte digest[RSA_MAX_SIZE / WOLFSSL_BIT_SIZE]; /* accessed in-place with size
4417 * key->dataLen
4418 */
4419#else
4420 byte digest[MAX_PKCS7_DIGEST_SZ];
4421#endif
4422 RsaKey key[1];
4423 DecodedCert dCert[1];
4424#endif
4425
4426 if (pkcs7 == NULL || sig == NULL || hash == NULL) {
4427 return BAD_FUNC_ARG;
4428 }
4429
4430#ifdef WOLFSSL_SMALL_STACK
4431 digest = (byte*)XMALLOC(MAX_PKCS7_DIGEST_SZ, pkcs7->heap,
4432 DYNAMIC_TYPE_TMP_BUFFER);
4433 if (digest == NULL)
4434 return MEMORY_E;
4435
4436 key = (RsaKey*)XMALLOC(sizeof(RsaKey), pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
4437 if (key == NULL) {
4438 XFREE(digest, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
4439 return MEMORY_E;
4440 }
4441
4442 dCert = (DecodedCert*)XMALLOC(sizeof(DecodedCert), pkcs7->heap,
4443 DYNAMIC_TYPE_DCERT);
4444 if (dCert == NULL) {
4445 XFREE(digest, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
4446 XFREE(key, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
4447 return MEMORY_E;
4448 }
4449#endif
4450
4451 XMEMSET(digest, 0, MAX_PKCS7_DIGEST_SZ);
4452
4453 /* loop over certs received in certificates set, try to find one
4454 * that will validate signature */
4455 for (i = 0; i < MAX_PKCS7_CERTS; i++) {
4456
4457 verified = 0;
4458 scratch = 0;
4459
4460 if (pkcs7->certSz[i] == 0)
4461 continue;
4462
4463 ret = wc_InitRsaKey_ex(key, pkcs7->heap, pkcs7->devId);
4464 if (ret != 0) {
4465 WC_FREE_VAR_EX(digest, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
4466 WC_FREE_VAR_EX(key, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
4467 WC_FREE_VAR_EX(dCert, pkcs7->heap, DYNAMIC_TYPE_DCERT);
4468 return ret;
4469 }
4470
4471 InitDecodedCert(dCert, pkcs7->cert[i], pkcs7->certSz[i], pkcs7->heap);
4472 /* not verifying, only using this to extract public key */
4473 ret = ParseCert(dCert, CA_TYPE, NO_VERIFY, 0);
4474 if (ret < 0) {
4475 WOLFSSL_MSG("ASN RSA cert parse error");
4476 FreeDecodedCert(dCert);
4477 wc_FreeRsaKey(key);
4478 continue;
4479 }
4480
4481 /* If the SignerInfo sid was parsed, only try the certificate whose
4482 * identity matches it. This binds the verifying public key to the
4483 * signer identity advertised in the CMS message and prevents signer
4484 * confusion when multiple certificates are embedded. */
4485 if (pkcs7->signerInfo != NULL && pkcs7->signerInfo->sid != NULL &&
4486 !wc_PKCS7_CertMatchesSignerInfo(pkcs7, dCert)) {
4487 FreeDecodedCert(dCert);
4488 wc_FreeRsaKey(key);
4489 continue;
4490 }
4491
4492 /* Defense in depth: the sid-matched cert must actually carry an
4493 * RSA-family key before we feed its SPKI to the RSA key decoder.
4494 * Rejecting here avoids depending on wc_RsaPublicKeyDecode to reject
4495 * wrong-type SPKIs. */
4496 if (dCert->keyOID != RSAk
4497 #ifdef WC_RSA_PSS
4498 && dCert->keyOID != RSAPSSk
4499 #endif
4500 ) {
4501 FreeDecodedCert(dCert);
4502 wc_FreeRsaKey(key);
4503 continue;
4504 }
4505
4506 if (wc_RsaPublicKeyDecode(dCert->publicKey, &scratch, key,
4507 dCert->pubKeySize) < 0) {
4508 WOLFSSL_MSG("ASN RSA key decode error");
4509 FreeDecodedCert(dCert);
4510 wc_FreeRsaKey(key);
4511 continue;
4512 }
4513
4514 #ifdef WOLFSSL_ASYNC_CRYPT
4515 do {
4516 ret = wc_AsyncWait(ret, &key->asyncDev,
4517 WC_ASYNC_FLAG_CALL_AGAIN);
4518 #endif
4519 if (ret >= 0) {
4520 ret = wc_RsaSSL_Verify(sig, (word32)sigSz, digest, MAX_PKCS7_DIGEST_SZ,
4521 key);
4522 }
4523 #ifdef WOLFSSL_ASYNC_CRYPT
4524 } while (ret == WC_NO_ERR_TRACE(WC_PENDING_E));
4525 #endif
4526 FreeDecodedCert(dCert);
4527 wc_FreeRsaKey(key);
4528
4529 if ((ret > 0) && (hashSz == (word32)ret)) {
4530 if (XMEMCMP(digest, hash, hashSz) == 0) {
4531 /* found signer that successfully verified signature */
4532 verified = 1;
4533 pkcs7->verifyCert = pkcs7->cert[i];
4534 pkcs7->verifyCertSz = pkcs7->certSz[i];
4535 break;
4536 }
4537 }
4538 }
4539
4540 if (verified == 0) {
4541 ret = SIG_VERIFY_E;
4542 }
4543
4544 WC_FREE_VAR_EX(digest, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
4545 WC_FREE_VAR_EX(key, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
4546 WC_FREE_VAR_EX(dCert, pkcs7->heap, DYNAMIC_TYPE_DCERT);
4547
4548 return ret;
4549}
4550
4551#if defined(WC_RSA_PSS)
4552/* returns 0 when signature verifies, negative on error */
4553static int wc_PKCS7_RsaPssVerify(wc_PKCS7* pkcs7, byte* sig, int sigSz,
4554 byte* hash, word32 hashSz)
4555{
4556 int ret = 0, i;
4557 word32 scratch = 0, verified = 0;
4558 word32 pkSz;
4559 int saltLen, verify;
4560 enum wc_HashType hashType;
4561 int hashDigSz, mgf;
4562 /* wc_RsaPSS_Verify_ex output is PSS-encoded message (RSA_PSS_PAD_SZ +
4563 * saltLen + 2*hLen bytes), which can exceed MAX_PKCS7_DIGEST_SZ.
4564 * Use MAX_ENCRYPTED_KEY_SZ (512) to cover RSA keys up to 4096-bit. */
4565 WC_DECLARE_VAR(digest, byte, MAX_ENCRYPTED_KEY_SZ, 0);
4566 WC_DECLARE_VAR(key, RsaKey, 1, 0);
4567 WC_DECLARE_VAR(dCert, DecodedCert, 1, 0);
4568
4569 if (pkcs7 == NULL || sig == NULL || hash == NULL)
4570 return BAD_FUNC_ARG;
4571
4572 /* Use SignerInfo.signatureAlgorithm params when decoded; else digestAlgo */
4573 if (pkcs7->pssParamsPresent)
4574 hashType = (enum wc_HashType)pkcs7->pssHashType;
4575 else
4576 hashType = wc_OidGetHash(pkcs7->hashOID);
4577 hashDigSz = wc_HashGetDigestSize(hashType);
4578 if (hashDigSz < 0)
4579 return ASN_PARSE_E;
4580 if (hashSz != (word32)hashDigSz)
4581 return ASN_PARSE_E;
4582 mgf = pkcs7->pssParamsPresent
4583 ? pkcs7->pssMgf : pkcs7_hash2mgf(hashType);
4584 if (mgf == WC_MGF1NONE)
4585 return ASN_PARSE_E;
4586
4587 WC_ALLOC_VAR_EX(digest, byte, MAX_ENCRYPTED_KEY_SZ, pkcs7->heap,
4588 DYNAMIC_TYPE_TMP_BUFFER, return MEMORY_E);
4589 WC_ALLOC_VAR_EX(key, RsaKey, 1, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER,
4590 { WC_FREE_VAR_EX(digest, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
4591 return MEMORY_E; });
4592 WC_ALLOC_VAR_EX(dCert, DecodedCert, 1, pkcs7->heap, DYNAMIC_TYPE_DCERT,
4593 { WC_FREE_VAR_EX(digest, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
4594 WC_FREE_VAR_EX(key, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
4595 return MEMORY_E; });
4596
4597 XMEMSET(digest, 0, MAX_ENCRYPTED_KEY_SZ);
4598
4599 for (i = 0; i < MAX_PKCS7_CERTS; i++) {
4600 if (pkcs7->certSz[i] == 0)
4601 continue;
4602
4603 scratch = 0;
4604 ret = wc_InitRsaKey_ex(key, pkcs7->heap, pkcs7->devId);
4605 if (ret != 0)
4606 break;
4607
4608 InitDecodedCert(dCert, pkcs7->cert[i], pkcs7->certSz[i], pkcs7->heap);
4609 ret = ParseCert(dCert, CA_TYPE, NO_VERIFY, 0);
4610 if (ret < 0) {
4611 FreeDecodedCert(dCert);
4612 wc_FreeRsaKey(key);
4613 continue;
4614 }
4615
4616 /* Only try the certificate identified by the SignerInfo sid (see
4617 * matching comment in wc_PKCS7_RsaVerify). */
4618 if (pkcs7->signerInfo != NULL && pkcs7->signerInfo->sid != NULL &&
4619 !wc_PKCS7_CertMatchesSignerInfo(pkcs7, dCert)) {
4620 FreeDecodedCert(dCert);
4621 wc_FreeRsaKey(key);
4622 continue;
4623 }
4624
4625 /* Defense in depth: reject non-RSA SPKIs before key decode. RSA
4626 * rsaEncryption certs (keyOID=RSAk) are accepted for PSS signatures
4627 * per RFC 8017 - a RSASSA-PSS cert is not required. */
4628 if (dCert->keyOID != RSAk && dCert->keyOID != RSAPSSk) {
4629 FreeDecodedCert(dCert);
4630 wc_FreeRsaKey(key);
4631 continue;
4632 }
4633
4634 pkSz = dCert->pubKeySize;
4635 if (pkSz > (MAX_RSA_INT_SZ + MAX_RSA_E_SZ))
4636 pkSz = (MAX_RSA_INT_SZ + MAX_RSA_E_SZ);
4637
4638 if (wc_RsaPublicKeyDecode(dCert->publicKey, &scratch, key,
4639 pkSz) < 0) {
4640 FreeDecodedCert(dCert);
4641 wc_FreeRsaKey(key);
4642 continue;
4643 }
4644
4645 saltLen = pkcs7->pssParamsPresent
4646 ? pkcs7->pssSaltLen : RSA_PSS_SALT_LEN_DEFAULT;
4647
4648 /* wc_RsaPSS_Verify_ex returns PSS encoded message length, not
4649 * the recovered hash. Must then call wc_RsaPSS_CheckPadding_ex
4650 * to verify the PSS padding against the expected hash. */
4651 verify = wc_RsaPSS_Verify_ex(sig, (word32)sigSz, digest,
4652 MAX_ENCRYPTED_KEY_SZ,
4653 hashType, mgf, saltLen, key);
4654 if (verify > 0) {
4655 /* wc_RsaPSS_CheckPadding_ex signature varies across
4656 * FIPS / selftest versions; match the pattern in asn.c */
4657 #if (defined(HAVE_SELFTEST) && \
4658 (!defined(HAVE_SELFTEST_VERSION) || \
4659 (HAVE_SELFTEST_VERSION < 2))) || \
4660 (defined(HAVE_FIPS) && defined(HAVE_FIPS_VERSION) && \
4661 (HAVE_FIPS_VERSION < 2))
4662 ret = wc_RsaPSS_CheckPadding_ex(hash, hashSz, digest,
4663 (word32)verify, hashType,
4664 saltLen);
4665 #elif (defined(HAVE_SELFTEST) && \
4666 (HAVE_SELFTEST_VERSION == 2)) || \
4667 (defined(HAVE_FIPS) && defined(HAVE_FIPS_VERSION) && \
4668 (HAVE_FIPS_VERSION == 2))
4669 ret = wc_RsaPSS_CheckPadding_ex(hash, hashSz, digest,
4670 (word32)verify, hashType,
4671 saltLen, 0);
4672 #else
4673 ret = wc_RsaPSS_CheckPadding_ex2(hash, hashSz, digest,
4674 (word32)verify, hashType,
4675 saltLen,
4676 mp_count_bits(&key->n),
4677 pkcs7->heap);
4678 #endif
4679 }
4680 else {
4681 ret = verify;
4682 }
4683
4684 FreeDecodedCert(dCert);
4685 wc_FreeRsaKey(key);
4686
4687 if (ret == 0) {
4688 verified = 1;
4689 pkcs7->verifyCert = pkcs7->cert[i];
4690 pkcs7->verifyCertSz = pkcs7->certSz[i];
4691 break;
4692 }
4693 ret = 0;
4694 }
4695
4696 if (verified == 0)
4697 ret = SIG_VERIFY_E;
4698
4699 WC_FREE_VAR_EX(digest, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
4700 WC_FREE_VAR_EX(key, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
4701 WC_FREE_VAR_EX(dCert, pkcs7->heap, DYNAMIC_TYPE_DCERT);
4702
4703 return ret;
4704}
4705#endif /* WC_RSA_PSS */
4706
4707#endif /* NO_RSA */
4708
4709
4710#ifdef HAVE_ECC
4711
4712/* returns size of signature put into out, negative on error */
4713static int wc_PKCS7_EcdsaVerify(wc_PKCS7* pkcs7, byte* sig, int sigSz,
4714 byte* hash, word32 hashSz)
4715{
4716 int ret = 0, i;
4717 int res = 0;
4718 int verified = 0;
4719#ifdef WOLFSSL_SMALL_STACK
4720 byte* digest;
4721 ecc_key* key;
4722 DecodedCert* dCert;
4723#else
4724 byte digest[MAX_PKCS7_DIGEST_SZ];
4725 ecc_key key[1];
4726 DecodedCert dCert[1];
4727#endif
4728 word32 idx = 0;
4729
4730 if (pkcs7 == NULL || sig == NULL)
4731 return BAD_FUNC_ARG;
4732
4733 /* Check hash length */
4734 if ((hashSz > WC_MAX_DIGEST_SIZE) ||
4735 (hashSz < WC_MIN_DIGEST_SIZE)) {
4736 return BAD_LENGTH_E;
4737 }
4738
4739#ifdef WOLFSSL_SMALL_STACK
4740 digest = (byte*)XMALLOC(MAX_PKCS7_DIGEST_SZ, pkcs7->heap,
4741 DYNAMIC_TYPE_TMP_BUFFER);
4742 if (digest == NULL)
4743 return MEMORY_E;
4744
4745 key = (ecc_key*)XMALLOC(sizeof(ecc_key), pkcs7->heap,
4746 DYNAMIC_TYPE_TMP_BUFFER);
4747 if (key == NULL) {
4748 XFREE(digest, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
4749 return MEMORY_E;
4750 }
4751
4752 dCert = (DecodedCert*)XMALLOC(sizeof(DecodedCert), pkcs7->heap,
4753 DYNAMIC_TYPE_DCERT);
4754 if (dCert == NULL) {
4755 XFREE(digest, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
4756 XFREE(key, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
4757 return MEMORY_E;
4758 }
4759#endif
4760
4761 XMEMSET(digest, 0, MAX_PKCS7_DIGEST_SZ);
4762
4763 /* loop over certs received in certificates set, try to find one
4764 * that will validate signature */
4765 for (i = 0; i < MAX_PKCS7_CERTS; i++) {
4766
4767 verified = 0;
4768 idx = 0;
4769
4770 if (pkcs7->certSz[i] == 0)
4771 continue;
4772
4773 ret = wc_ecc_init_ex(key, pkcs7->heap, pkcs7->devId);
4774 if (ret != 0) {
4775 WC_FREE_VAR_EX(digest, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
4776 WC_FREE_VAR_EX(key, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
4777 WC_FREE_VAR_EX(dCert, pkcs7->heap, DYNAMIC_TYPE_DCERT);
4778 return ret;
4779 }
4780
4781 InitDecodedCert(dCert, pkcs7->cert[i], pkcs7->certSz[i], pkcs7->heap);
4782
4783 /* This allows the user to not error out in the case of extensions that
4784 * we are not aware of. */
4785#ifdef WC_ASN_UNKNOWN_EXT_CB
4786 if (pkcs7->unknownExtCallback != NULL)
4787 wc_SetUnknownExtCallback(dCert, pkcs7->unknownExtCallback);
4788#endif
4789
4790 /* not verifying, only using this to extract public key */
4791 ret = ParseCert(dCert, CA_TYPE, NO_VERIFY, 0);
4792 if (ret < 0) {
4793 WOLFSSL_MSG("ASN ECC cert parse error");
4794 FreeDecodedCert(dCert);
4795 wc_ecc_free(key);
4796 continue;
4797 }
4798
4799 /* Only try the certificate identified by the SignerInfo sid (see
4800 * matching comment in wc_PKCS7_RsaVerify). */
4801 if (pkcs7->signerInfo != NULL && pkcs7->signerInfo->sid != NULL &&
4802 !wc_PKCS7_CertMatchesSignerInfo(pkcs7, dCert)) {
4803 FreeDecodedCert(dCert);
4804 wc_ecc_free(key);
4805 continue;
4806 }
4807
4808 /* Defense in depth: reject non-ECDSA SPKIs before key decode. */
4809 if (dCert->keyOID != ECDSAk) {
4810 FreeDecodedCert(dCert);
4811 wc_ecc_free(key);
4812 continue;
4813 }
4814
4815 if (wc_EccPublicKeyDecode(dCert->publicKey, &idx, key,
4816 dCert->pubKeySize) < 0) {
4817 WOLFSSL_MSG("ASN ECC key decode error");
4818 FreeDecodedCert(dCert);
4819 wc_ecc_free(key);
4820 continue;
4821 }
4822
4823 #ifdef WOLFSSL_ASYNC_CRYPT
4824 do {
4825 ret = wc_AsyncWait(ret, &key->asyncDev,
4826 WC_ASYNC_FLAG_CALL_AGAIN);
4827 #endif
4828 if (ret >= 0) {
4829 ret = wc_ecc_verify_hash(sig, (word32)sigSz, hash, hashSz, &res, key);
4830 }
4831 #ifdef WOLFSSL_ASYNC_CRYPT
4832 } while (ret == WC_NO_ERR_TRACE(WC_PENDING_E));
4833 #endif
4834
4835 if (ret == 0 && res == 1) {
4836 /* found signer that successfully verified signature */
4837 verified = 1;
4838 XMEMCPY(pkcs7->issuerSubjKeyId, dCert->extSubjKeyId, KEYID_SIZE);
4839 pkcs7->verifyCert = pkcs7->cert[i];
4840 pkcs7->verifyCertSz = pkcs7->certSz[i];
4841 }
4842
4843 wc_ecc_free(key);
4844 FreeDecodedCert(dCert);
4845
4846 if (ret == 0 && res == 1) {
4847 break;
4848 }
4849 }
4850
4851 if (verified == 0) {
4852 ret = SIG_VERIFY_E;
4853 }
4854
4855 WC_FREE_VAR_EX(digest, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
4856 WC_FREE_VAR_EX(key, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
4857 WC_FREE_VAR_EX(dCert, pkcs7->heap, DYNAMIC_TYPE_DCERT);
4858
4859 return ret;
4860}
4861
4862#endif /* HAVE_ECC */
4863
4864
4865/* build SignedData digest, both in PKCS#7 DigestInfo format and
4866 * as plain digest for CMS.
4867 *
4868 * pkcs7 - pointer to initialized PKCS7 struct
4869 * signedAttrib - signed attributes
4870 * signedAttribSz - size of signedAttrib, octets
4871 * pkcs7Digest - [OUT] PKCS#7 DigestInfo
4872 * pkcs7DigestSz - [IN/OUT] size of pkcs7Digest
4873 * plainDigest - [OUT] pointer to plain digest, offset into pkcs7Digest
4874 * plainDigestSz - [OUT] size of digest at plainDigest
4875 *
4876 * returns 0 on success, negative on error */
4877static int wc_PKCS7_BuildSignedDataDigest(wc_PKCS7* pkcs7, byte* signedAttrib,
4878 word32 signedAttribSz, byte* pkcs7Digest,
4879 word32* pkcs7DigestSz, byte** plainDigest,
4880 word32* plainDigestSz,
4881 const byte* hashBuf, word32 hashBufSz)
4882{
4883 int ret = 0, digIdx = 0;
4884 word32 attribSetSz = 0, hashSz = 0;
4885 byte attribSet[MAX_SET_SZ];
4886 byte digest[WC_MAX_DIGEST_SIZE];
4887 byte digestInfoSeq[MAX_SEQ_SZ];
4888 byte digestStr[MAX_OCTET_STR_SZ];
4889 byte algoId[MAX_ALGO_SZ];
4890 word32 digestInfoSeqSz, digestStrSz, algoIdSz;
4891 WC_DECLARE_VAR(digestInfo, byte, MAX_PKCS7_DIGEST_SZ, 0);
4892 WC_DECLARE_VAR(hash, wc_HashAlg, 1, pkcs7 ? pkcs7->heap : NULL);
4893 enum wc_HashType hashType;
4894
4895 /* check arguments */
4896 if (pkcs7 == NULL || pkcs7Digest == NULL ||
4897 pkcs7DigestSz == NULL || plainDigest == NULL) {
4898 return BAD_FUNC_ARG;
4899 }
4900
4901 hashType = wc_OidGetHash(pkcs7->hashOID);
4902 ret = wc_HashGetDigestSize(hashType);
4903 if (ret < 0)
4904 return ret;
4905 hashSz = (word32)ret;
4906
4907 if (signedAttribSz > 0) {
4908 if (signedAttrib == NULL)
4909 return BAD_FUNC_ARG;
4910 }
4911 else {
4912 if (hashBuf && hashBufSz > 0) {
4913 if (hashSz != hashBufSz)
4914 return BAD_FUNC_ARG;
4915 }
4916 else if (pkcs7->content == NULL)
4917 return BAD_FUNC_ARG;
4918 }
4919
4920 WC_ALLOC_VAR_EX(digestInfo, byte, MAX_PKCS7_DIGEST_SZ, pkcs7->heap,
4921 DYNAMIC_TYPE_TMP_BUFFER, return MEMORY_E);
4922 WC_ALLOC_VAR_EX(hash, wc_HashAlg, 1, pkcs7->heap, DYNAMIC_TYPE_HASHES,
4923 { WC_FREE_VAR_EX(digestInfo, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
4924 return MEMORY_E; });
4925
4926 XMEMSET(pkcs7Digest, 0, *pkcs7DigestSz);
4927 XMEMSET(digest, 0, WC_MAX_DIGEST_SIZE);
4928 XMEMSET(digestInfo, 0, MAX_PKCS7_DIGEST_SZ);
4929
4930
4931 /* calculate digest */
4932 if (hashBuf && hashBufSz > 0 && signedAttribSz == 0) {
4933 XMEMCPY(digest, hashBuf, hashBufSz);
4934 }
4935 else {
4936 ret = wc_HashInit(hash, hashType);
4937 if (ret < 0) {
4938 WC_FREE_VAR_EX(digestInfo, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
4939 WC_FREE_VAR_EX(hash, pkcs7->heap, DYNAMIC_TYPE_HASHES);
4940 return ret;
4941 }
4942
4943 if (signedAttribSz > 0) {
4944 attribSetSz = SetSet(signedAttribSz, attribSet);
4945
4946 /* calculate digest */
4947 ret = wc_HashUpdate(hash, hashType, attribSet, attribSetSz);
4948 if (ret == 0)
4949 ret = wc_HashUpdate(hash, hashType, signedAttrib, signedAttribSz);
4950 if (ret == 0)
4951 ret = wc_HashFinal(hash, hashType, digest);
4952 } else {
4953 ret = wc_HashUpdate(hash, hashType, pkcs7->content, pkcs7->contentSz);
4954 if (ret == 0)
4955 ret = wc_HashFinal(hash, hashType, digest);
4956 }
4957
4958 wc_HashFree(hash, hashType);
4959 if (ret < 0) {
4960 WC_FREE_VAR_EX(digestInfo, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
4961 WC_FREE_VAR_EX(hash, pkcs7->heap, DYNAMIC_TYPE_HASHES);
4962 return ret;
4963 }
4964 }
4965
4966 /* Set algoID, match whatever was input to match either NULL or absent */
4967 algoIdSz = SetAlgoIDEx(pkcs7->hashOID, algoId, oidHashType,
4968 0, pkcs7->hashParamsAbsent);
4969
4970 digestStrSz = SetOctetString(hashSz, digestStr);
4971 digestInfoSeqSz = SetSequence(algoIdSz + digestStrSz + hashSz,
4972 digestInfoSeq);
4973
4974 XMEMCPY(digestInfo + digIdx, digestInfoSeq, digestInfoSeqSz);
4975 digIdx += (int)digestInfoSeqSz;
4976 XMEMCPY(digestInfo + digIdx, algoId, algoIdSz);
4977 digIdx += (int)algoIdSz;
4978 XMEMCPY(digestInfo + digIdx, digestStr, digestStrSz);
4979 digIdx += (int)digestStrSz;
4980 XMEMCPY(digestInfo + digIdx, digest, hashSz);
4981 digIdx += (int)hashSz;
4982
4983 XMEMCPY(pkcs7Digest, digestInfo, (word32)digIdx);
4984 *pkcs7DigestSz = (word32)digIdx;
4985
4986 /* set plain digest pointer */
4987 *plainDigest = pkcs7Digest + digIdx - hashSz;
4988 *plainDigestSz = hashSz;
4989
4990 WC_FREE_VAR_EX(digestInfo, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
4991 WC_FREE_VAR_EX(hash, pkcs7->heap, DYNAMIC_TYPE_HASHES);
4992 return 0;
4993}
4994
4995
4996/* Verifies CMS/PKCS7 SignedData content digest matches that which is
4997 * included in the messageDigest signed attribute. Only called when
4998 * signed attributes are present, otherwise original signature verification
4999 * is done over content.
5000 *
5001 * pkcs7 - pointer to initialized PKCS7 struct
5002 * hashBuf - pointer to user-provided hash buffer, used with
5003 * wc_PKCS7_VerifySignedData_ex()
5004 * hashBufSz - size of hashBuf, octets
5005 *
5006 * return 0 on success, negative on error */
5007static int wc_PKCS7_VerifyContentMessageDigest(wc_PKCS7* pkcs7,
5008 const byte* hashBuf,
5009 word32 hashSz)
5010{
5011 int ret = 0, digestSz = 0, innerAttribSz = 0;
5012 int contentLen = 0;
5013 word32 idx = 0;
5014 word32 contentIdx = 0;
5015 byte* content = NULL;
5016 const byte* digestBuf = NULL;
5017 WC_DECLARE_VAR(digest, byte, MAX_PKCS7_DIGEST_SZ, 0);
5018 PKCS7DecodedAttrib* attrib;
5019 enum wc_HashType hashType;
5020
5021 /* messageDigest OID (1.2.840.113549.1.9.4) */
5022 const byte mdOid[] =
5023 { 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x04 };
5024
5025 if (pkcs7 == NULL)
5026 return BAD_FUNC_ARG;
5027
5028 if ((pkcs7->content == NULL || pkcs7->contentSz == 0) &&
5029 (hashBuf == NULL || hashSz == 0)) {
5030 WOLFSSL_MSG("SignedData bundle has no content or hash to verify");
5031 return BAD_FUNC_ARG;
5032 }
5033
5034 /* lookup messageDigest attribute */
5035 attrib = findAttrib(pkcs7, mdOid, sizeof(mdOid));
5036 if (attrib == NULL) {
5037 WOLFSSL_MSG("messageDigest attribute not in bundle, must be when "
5038 "signed attribs are present");
5039 return ASN_PARSE_E;
5040 }
5041
5042 /* advance past attrib->value ASN.1 header and length */
5043 if (attrib->value == NULL || attrib->valueSz == 0)
5044 return ASN_PARSE_E;
5045
5046 if (attrib->value[idx++] != ASN_OCTET_STRING)
5047 return ASN_PARSE_E;
5048
5049 if (GetLength(attrib->value, &idx, &innerAttribSz, attrib->valueSz) < 0)
5050 return ASN_PARSE_E;
5051
5052 /* get hash type and size */
5053 hashType = wc_OidGetHash(pkcs7->hashOID);
5054 if (hashType == WC_HASH_TYPE_NONE) {
5055 WOLFSSL_MSG("Error getting hash type for PKCS7 content verification");
5056 return BAD_FUNC_ARG;
5057 }
5058
5059 /* build content hash if needed, or use existing hash value */
5060 if (hashBuf == NULL) {
5061
5062 WC_ALLOC_VAR_EX(digest, byte, MAX_PKCS7_DIGEST_SZ, pkcs7->heap,
5063 DYNAMIC_TYPE_TMP_BUFFER, return MEMORY_E);
5064 XMEMSET(digest, 0, MAX_PKCS7_DIGEST_SZ);
5065
5066 content = pkcs7->content;
5067 contentLen = (int)pkcs7->contentSz;
5068
5069 if (pkcs7->contentIsPkcs7Type == 1) {
5070 /* Content follows PKCS#7 RFC, which defines type as ANY. CMS
5071 * mandates OCTET_STRING which has already been stripped off.
5072 * For PKCS#7 message digest calculation, digest is calculated
5073 * only on the "value" of the DER encoding. As such, advance past
5074 * the tag and length */
5075 if (contentLen > 1) {
5076 contentIdx++;
5077 }
5078
5079 if (GetLength_ex(content, &contentIdx, &contentLen,
5080 (word32)contentLen, 1) < 0) {
5081 WC_FREE_VAR_EX(digest, pkcs7->heap,
5082 DYNAMIC_TYPE_TMP_BUFFER);
5083 return ASN_PARSE_E;
5084 }
5085 }
5086
5087 ret = wc_Hash(hashType, content + contentIdx, (word32)contentLen, digest,
5088 MAX_PKCS7_DIGEST_SZ);
5089 if (ret < 0) {
5090 WOLFSSL_MSG("Error hashing PKCS7 content for verification");
5091 WC_FREE_VAR_EX(digest, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
5092 return ret;
5093 }
5094
5095 digestBuf = digest;
5096 digestSz = wc_HashGetDigestSize(hashType);
5097 if (digestSz < 0) {
5098 WOLFSSL_MSG("Invalid hash type");
5099 WC_FREE_VAR_EX(digest, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
5100 return digestSz;
5101 }
5102 } else {
5103
5104 /* user passed in pre-computed hash */
5105 digestBuf = (const byte*)hashBuf;
5106 digestSz = (int)hashSz;
5107 }
5108
5109 /* compare generated to hash in messageDigest attribute */
5110 if ((innerAttribSz != digestSz) ||
5111 (XMEMCMP(attrib->value + idx, digestBuf, (size_t)digestSz) != 0)) {
5112 WOLFSSL_MSG("Content digest does not match messageDigest attrib value");
5113 WC_FREE_VAR_EX(digest, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
5114 return SIG_VERIFY_E;
5115 }
5116
5117 if (hashBuf == NULL) {
5118 WC_FREE_VAR_EX(digest, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
5119 }
5120
5121 return 0;
5122}
5123
5124
5125/* verifies SignedData signature, over either PKCS#7 DigestInfo or
5126 * content digest.
5127 *
5128 * pkcs7 - pointer to initialized PKCS7 struct
5129 * sig - signature to verify
5130 * sigSz - size of sig
5131 * signedAttrib - signed attributes, or null if empty
5132 * signedAttribSz - size of signedAttributes
5133 *
5134 * return 0 on success, negative on error */
5135static int wc_PKCS7_SignedDataVerifySignature(wc_PKCS7* pkcs7, byte* sig,
5136 word32 sigSz, byte* signedAttrib,
5137 word32 signedAttribSz,
5138 const byte* hashBuf, word32 hashSz)
5139{
5140 int ret = 0;
5141 word32 plainDigestSz = 0, pkcs7DigestSz;
5142 byte* plainDigest = NULL; /* offset into pkcs7Digest */
5143 WC_DECLARE_VAR(pkcs7Digest, byte, MAX_PKCS7_DIGEST_SZ, 0);
5144
5145 if (pkcs7 == NULL)
5146 return BAD_FUNC_ARG;
5147
5148 /* allocate space to build hash */
5149 pkcs7DigestSz = MAX_PKCS7_DIGEST_SZ;
5150 WC_ALLOC_VAR_EX(pkcs7Digest, byte, pkcs7DigestSz, pkcs7->heap,
5151 DYNAMIC_TYPE_TMP_BUFFER, return MEMORY_E);
5152
5153 XMEMSET(pkcs7Digest, 0, pkcs7DigestSz);
5154
5155 /* verify signed attrib digest matches that of content */
5156 if (signedAttrib != NULL) {
5157 ret = wc_PKCS7_VerifyContentMessageDigest(pkcs7, hashBuf, hashSz);
5158 if (ret != 0) {
5159 WC_FREE_VAR_EX(pkcs7Digest, pkcs7->heap,
5160 DYNAMIC_TYPE_TMP_BUFFER);
5161 return ret;
5162 }
5163 }
5164
5165 /* build hash to verify against */
5166 ret = wc_PKCS7_BuildSignedDataDigest(pkcs7, signedAttrib,
5167 signedAttribSz, pkcs7Digest,
5168 &pkcs7DigestSz, &plainDigest,
5169 &plainDigestSz, hashBuf, hashSz);
5170 if (ret < 0) {
5171 WC_FREE_VAR_EX(pkcs7Digest, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
5172 return ret;
5173 }
5174
5175 /* If no certificates are available then store the signature and hash for
5176 * user to verify. Make sure that different return value than success is
5177 * returned because the signature was not verified here. */
5178 if (ret == 0) {
5179 byte haveCert = 0;
5180 int i;
5181
5182 for (i = 0; i < MAX_PKCS7_CERTS; i++) {
5183 if (pkcs7->certSz[i] == 0)
5184 continue;
5185 haveCert = 1;
5186 }
5187
5188 if (!haveCert) {
5189 WOLFSSL_MSG("No certificates in bundle to verify signature");
5190
5191 /* store signature */
5192 XFREE(pkcs7->signature, pkcs7->heap, DYNAMIC_TYPE_SIGNATURE);
5193 pkcs7->signature = NULL;
5194 pkcs7->signatureSz = 0;
5195 pkcs7->signature = (byte*)XMALLOC(sigSz, pkcs7->heap,
5196 DYNAMIC_TYPE_SIGNATURE);
5197 if (pkcs7->signature == NULL) {
5198 WC_FREE_VAR_EX(pkcs7Digest, pkcs7->heap,
5199 DYNAMIC_TYPE_TMP_BUFFER);
5200 return MEMORY_E;
5201 }
5202 XMEMCPY(pkcs7->signature, sig, sigSz);
5203 pkcs7->signatureSz = sigSz;
5204
5205 /* store plain digest (CMS and ECC) */
5206 XFREE(pkcs7->plainDigest, pkcs7->heap, DYNAMIC_TYPE_DIGEST);
5207 pkcs7->plainDigest = NULL;
5208 pkcs7->plainDigestSz = 0;
5209 pkcs7->plainDigest = (byte*)XMALLOC(plainDigestSz, pkcs7->heap,
5210 DYNAMIC_TYPE_DIGEST);
5211 if (pkcs7->plainDigest == NULL) {
5212 WC_FREE_VAR_EX(pkcs7Digest, pkcs7->heap,
5213 DYNAMIC_TYPE_TMP_BUFFER);
5214 return MEMORY_E;
5215 }
5216 XMEMCPY(pkcs7->plainDigest, plainDigest, plainDigestSz);
5217 pkcs7->plainDigestSz = plainDigestSz;
5218
5219 /* store pkcs7 digest (default RSA) */
5220 XFREE(pkcs7->pkcs7Digest, pkcs7->heap, DYNAMIC_TYPE_DIGEST);
5221 pkcs7->pkcs7Digest = NULL;
5222 pkcs7->pkcs7DigestSz = 0;
5223 pkcs7->pkcs7Digest = (byte*)XMALLOC(pkcs7DigestSz, pkcs7->heap,
5224 DYNAMIC_TYPE_DIGEST);
5225 if (pkcs7->pkcs7Digest == NULL) {
5226 WC_FREE_VAR_EX(pkcs7Digest, pkcs7->heap,
5227 DYNAMIC_TYPE_TMP_BUFFER);
5228 return MEMORY_E;
5229 }
5230 XMEMCPY(pkcs7->pkcs7Digest, pkcs7Digest, pkcs7DigestSz);
5231 pkcs7->pkcs7DigestSz = pkcs7DigestSz;
5232
5233 WC_FREE_VAR_EX(pkcs7Digest, pkcs7->heap,
5234 DYNAMIC_TYPE_TMP_BUFFER);
5235 return PKCS7_SIGNEEDS_CHECK;
5236 }
5237 }
5238
5239
5240
5241 switch (pkcs7->publicKeyOID) {
5242
5243#ifndef NO_RSA
5244 case RSAk:
5245 ret = wc_PKCS7_RsaVerify(pkcs7, sig, (int)sigSz, pkcs7Digest,
5246 pkcs7DigestSz);
5247 if (ret < 0) {
5248 WOLFSSL_MSG("PKCS#7 verification failed, trying CMS");
5249 ret = wc_PKCS7_RsaVerify(pkcs7, sig, (int)sigSz, plainDigest,
5250 plainDigestSz);
5251 }
5252 break;
5253
5254 #ifdef WC_RSA_PSS
5255 /* RSA-PSS signs the raw hash (plainDigest), not DigestInfo */
5256 case RSAPSSk:
5257 ret = wc_PKCS7_RsaPssVerify(pkcs7, sig, (int)sigSz, plainDigest,
5258 plainDigestSz);
5259 break;
5260 #endif
5261#endif
5262
5263#ifdef HAVE_ECC
5264 case ECDSAk:
5265 ret = wc_PKCS7_EcdsaVerify(pkcs7, sig, (int)sigSz, plainDigest,
5266 plainDigestSz);
5267 break;
5268#endif
5269
5270 default:
5271 WOLFSSL_MSG("Unsupported public key type");
5272 ret = BAD_FUNC_ARG;
5273 }
5274
5275 WC_FREE_VAR_EX(pkcs7Digest, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
5276 return ret;
5277}
5278
5279
5280/* set correct public key OID based on signature OID, stores in
5281 * pkcs7->publicKeyOID and returns same value */
5282static int wc_PKCS7_SetPublicKeyOID(wc_PKCS7* pkcs7, int sigOID)
5283{
5284 if (pkcs7 == NULL)
5285 return BAD_FUNC_ARG;
5286
5287 pkcs7->publicKeyOID = 0;
5288
5289 switch (sigOID) {
5290
5291 #ifndef NO_RSA
5292 /* RSA signature types */
5293 case CTC_MD2wRSA:
5294 case CTC_MD5wRSA:
5295 case CTC_SHAwRSA:
5296 case CTC_SHA224wRSA:
5297 case CTC_SHA256wRSA:
5298 case CTC_SHA384wRSA:
5299 case CTC_SHA512wRSA:
5300 case CTC_SHA3_224wRSA:
5301 case CTC_SHA3_256wRSA:
5302 case CTC_SHA3_384wRSA:
5303 case CTC_SHA3_512wRSA:
5304 pkcs7->publicKeyOID = RSAk;
5305 break;
5306
5307 #ifdef WC_RSA_PSS
5308 /* CTC_RSASSAPSS and RSAPSSk are the same OID value */
5309 case CTC_RSASSAPSS:
5310 pkcs7->publicKeyOID = RSAPSSk;
5311 break;
5312 #endif
5313
5314 /* if sigOID is already RSAk */
5315 case RSAk:
5316 pkcs7->publicKeyOID = (word32)sigOID;
5317 break;
5318 #endif
5319
5320 #ifndef NO_DSA
5321 /* DSA signature types */
5322 case CTC_SHAwDSA:
5323 pkcs7->publicKeyOID = DSAk;
5324 break;
5325
5326 /* if sigOID is already DSAk */
5327 case DSAk:
5328 pkcs7->publicKeyOID = (word32)sigOID;
5329 break;
5330 #endif
5331
5332 #ifdef HAVE_ECC
5333 /* ECDSA signature types */
5334 case CTC_SHAwECDSA:
5335 case CTC_SHA224wECDSA:
5336 case CTC_SHA256wECDSA:
5337 case CTC_SHA384wECDSA:
5338 case CTC_SHA512wECDSA:
5339 case CTC_SHA3_224wECDSA:
5340 case CTC_SHA3_256wECDSA:
5341 case CTC_SHA3_384wECDSA:
5342 case CTC_SHA3_512wECDSA:
5343 pkcs7->publicKeyOID = ECDSAk;
5344 break;
5345
5346 /* if sigOID is already ECDSAk */
5347 case ECDSAk:
5348 pkcs7->publicKeyOID = (word32)sigOID;
5349 break;
5350 #endif
5351
5352 default:
5353 WOLFSSL_MSG("Unsupported public key algorithm");
5354 return ASN_SIG_KEY_E;
5355 }
5356
5357 return (int)pkcs7->publicKeyOID;
5358}
5359
5360
5361/* Parses through the attributes and adds them to the PKCS7 structure
5362 * Creates dynamic attribute structures that are free'd with calling
5363 * wc_PKCS7_Free()
5364 *
5365 * NOTE: An attribute has the ASN1 format of
5366 ** Sequence
5367 ****** Object ID
5368 ****** Set
5369 ********** {PrintableString, UTCTime, OCTET STRING ...}
5370 *
5371 * pkcs7 the PKCS7 structure to put the parsed attributes into
5372 * in buffer holding all attributes
5373 * inSz size of in buffer
5374 *
5375 * returns the number of attributes parsed on success
5376 */
5377static int wc_PKCS7_ParseAttribs(wc_PKCS7* pkcs7, byte* in, int inSz)
5378{
5379 int found = 0;
5380 word32 idx = 0;
5381 word32 oid;
5382
5383 if (pkcs7 == NULL || in == NULL || inSz < 0) {
5384 return BAD_FUNC_ARG;
5385 }
5386
5387 while (idx < (word32)inSz) {
5388 int length = 0;
5389 word32 oidIdx;
5390 PKCS7DecodedAttrib* attrib;
5391
5392 if (GetSequence(in, &idx, &length, (word32)inSz) < 0)
5393 return ASN_PARSE_E;
5394
5395 attrib = (PKCS7DecodedAttrib*)XMALLOC(sizeof(PKCS7DecodedAttrib),
5396 pkcs7->heap, DYNAMIC_TYPE_PKCS7);
5397 if (attrib == NULL) {
5398 return MEMORY_E;
5399 }
5400 XMEMSET(attrib, 0, sizeof(PKCS7DecodedAttrib));
5401
5402 oidIdx = idx;
5403 if (GetObjectId(in, &idx, &oid, oidIgnoreType, (word32)inSz)
5404 < 0) {
5405 XFREE(attrib, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
5406 return ASN_PARSE_E;
5407 }
5408 attrib->oidSz = idx - oidIdx;
5409 attrib->oid = (byte*)XMALLOC(attrib->oidSz, pkcs7->heap,
5410 DYNAMIC_TYPE_PKCS7);
5411 if (attrib->oid == NULL) {
5412 XFREE(attrib, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
5413 return MEMORY_E;
5414 }
5415 XMEMCPY(attrib->oid, in + oidIdx, attrib->oidSz);
5416
5417 /* Get Set that contains the printable string value */
5418 if (GetSet(in, &idx, &length, (word32)inSz) < 0) {
5419 XFREE(attrib->oid, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
5420 XFREE(attrib, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
5421 return ASN_PARSE_E;
5422 }
5423
5424 if ((inSz - (int)idx) < length) {
5425 XFREE(attrib->oid, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
5426 XFREE(attrib, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
5427 return ASN_PARSE_E;
5428 }
5429
5430 attrib->valueSz = (word32)length;
5431 attrib->value = (byte*)XMALLOC(attrib->valueSz, pkcs7->heap,
5432 DYNAMIC_TYPE_PKCS7);
5433 if (attrib->value == NULL) {
5434 XFREE(attrib->oid, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
5435 XFREE(attrib, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
5436 return MEMORY_E;
5437 }
5438 XMEMCPY(attrib->value, in + idx, attrib->valueSz);
5439 idx += (word32)length;
5440
5441 /* store attribute in linked list */
5442 if (pkcs7->decodedAttrib != NULL) {
5443 attrib->next = pkcs7->decodedAttrib;
5444 pkcs7->decodedAttrib = attrib;
5445 } else {
5446 pkcs7->decodedAttrib = attrib;
5447 }
5448 found++;
5449 }
5450
5451 return found;
5452}
5453
5454
5455/* option to turn off support for degenerate cases
5456 * flag 0 turns off support
5457 * flag 1 turns on support
5458 *
5459 * by default support for SignedData degenerate cases is on
5460 */
5461void wc_PKCS7_AllowDegenerate(wc_PKCS7* pkcs7, word16 flag)
5462{
5463 if (pkcs7) {
5464 if (flag) { /* flag of 1 turns on support for degenerate */
5465 pkcs7->noDegenerate = 0;
5466 }
5467 else { /* flag of 0 turns off support */
5468 pkcs7->noDegenerate = 1;
5469 }
5470 }
5471}
5472
5473/* Parses through a signerInfo set. Reads buffer "in" from "idxIn" to "idxIn" +
5474 * length treating the current "idxIn" plus the length of set as max possible
5475 * index.
5476 *
5477 * In the case that signed attributes are found "signedAttrib" gets set to point
5478 * at their location in the buffer "in". Also in this case signedAttribSz gets
5479 * set to the size of the signedAttrib buffer.
5480 *
5481 * returns 0 on success
5482 */
5483static int wc_PKCS7_ParseSignerInfo(wc_PKCS7* pkcs7, byte* in, word32 inSz,
5484 word32* idxIn, int degenerate, byte** signedAttrib, int* signedAttribSz)
5485{
5486 int ret = 0;
5487 int length = 0;
5488 int version = 0;
5489 word32 sigOID = 0, hashOID = 0;
5490 word32 idx = *idxIn, localIdx;
5491 byte tag;
5492 byte absentParams = FALSE;
5493
5494 WOLFSSL_ENTER("wc_PKCS7_ParseSignerInfo");
5495 /* require a signer if degenerate case not allowed */
5496 if (inSz == 0 && pkcs7->noDegenerate == 1) {
5497 WOLFSSL_MSG("Set to not allow degenerate cases");
5498 return PKCS7_NO_SIGNER_E;
5499 }
5500
5501 if (inSz == 0 && degenerate == 0) {
5502 WOLFSSL_MSG("PKCS7 signers expected");
5503 return PKCS7_NO_SIGNER_E;
5504 }
5505
5506 /* not a degenerate case and there is elements in the set */
5507 if (inSz > 0 && degenerate == 0) {
5508 ret = wc_PKCS7_SignerInfoNew(pkcs7);
5509
5510 /* Get the sequence of the first signerInfo */
5511 if (ret == 0 && GetSequence(in, &idx, &length, inSz) < 0)
5512 ret = ASN_PARSE_E;
5513
5514 /* Get the version */
5515 if (ret == 0 && GetMyVersion(in, &idx, &version, inSz) < 0)
5516 ret = ASN_PARSE_E;
5517
5518 if (ret == 0) {
5519 pkcs7->signerInfo->version = version;
5520 }
5521
5522 if (ret == 0 && version == 1) {
5523 /* Get the sequence of IssuerAndSerialNumber */
5524 if (GetSequence(in, &idx, &length, inSz) < 0)
5525 ret = ASN_PARSE_E;
5526
5527 if (ret == 0) {
5528 pkcs7->signerInfo->sidType = CMS_ISSUER_AND_SERIAL_NUMBER;
5529 ret = wc_PKCS7_SignerInfoSetSID(pkcs7, in + idx, length);
5530 idx += (word32)length;
5531 }
5532
5533 } else if (ret == 0 && version == 3) {
5534 /* Default: SignerInfo version 3 carries SubjectKeyIdentifier.
5535 * May be overridden below if the parser instead finds a
5536 * SEQUENCE (IssuerAndSerialNumber fallback). */
5537 pkcs7->signerInfo->sidType = CMS_SKID;
5538 /* Get the sequence of SubjectKeyIdentifier */
5539 if (idx + 1 > inSz)
5540 ret = BUFFER_E;
5541
5542 localIdx = idx;
5543 if (ret == 0 && GetASNTag(in, &localIdx, &tag, inSz) == 0 &&
5544 tag == (ASN_CONSTRUCTED | ASN_CONTEXT_SPECIFIC | 0)) {
5545 idx++;
5546
5547 if (GetLength(in, &idx, &length, inSz) <= 0)
5548 ret = ASN_PARSE_E;
5549
5550 if (ret == 0 && idx + 1 > inSz)
5551 ret = BUFFER_E;
5552
5553 if (ret == 0 && GetASNTag(in, &idx, &tag, inSz) < 0)
5554 ret = ASN_PARSE_E;
5555
5556 if (ret == 0 && tag != ASN_OCTET_STRING)
5557 ret = ASN_PARSE_E;
5558
5559 if (ret == 0 && GetLength(in, &idx, &length, inSz) < 0)
5560 ret = ASN_PARSE_E;
5561 }
5562 else {
5563 /* check if SKID with ASN_CONTEXT_SPECIFIC otherwise in version
5564 * 3 try to get issuerAndSerial */
5565 localIdx = idx;
5566 if (GetASNTag(in, &localIdx, &tag, inSz) == 0 &&
5567 tag == ASN_CONTEXT_SPECIFIC) {
5568 idx++;
5569 if (ret == 0 && GetLength(in, &idx, &length, inSz) < 0)
5570 ret = ASN_PARSE_E;
5571 }
5572 else {
5573 if (pkcs7->version != 3) {
5574 WOLFSSL_MSG("Unexpected signer info found with version");
5575 ret = ASN_PARSE_E;
5576 }
5577
5578 if (ret == 0 && GetSequence(in, &idx, &length, inSz) < 0)
5579 ret = ASN_PARSE_E;
5580
5581 if (ret == 0) {
5582 /* v3 carrying IssuerAndSerialNumber fallback */
5583 pkcs7->signerInfo->sidType =
5584 CMS_ISSUER_AND_SERIAL_NUMBER;
5585 }
5586 }
5587 }
5588
5589 if (ret == 0) {
5590 if (length > (int)inSz - (int)idx)
5591 ret = BUFFER_E;
5592 }
5593
5594 if (ret == 0) {
5595 ret = wc_PKCS7_SignerInfoSetSID(pkcs7, in + idx, length);
5596 idx += (word32)length;
5597 }
5598
5599 } else {
5600 WOLFSSL_MSG("PKCS#7 signerInfo version must be 1 or 3");
5601 ret = ASN_VERSION_E;
5602 }
5603
5604 /* Get the sequence of digestAlgorithm */
5605 if (ret == 0 && GetAlgoIdEx(in, &idx, &hashOID, oidHashType,
5606 inSz, &absentParams) < 0) {
5607 ret = ASN_PARSE_E;
5608 }
5609 pkcs7->hashOID = (int)hashOID;
5610 pkcs7->hashParamsAbsent = (absentParams != 0);
5611
5612 /* Get the IMPLICIT[0] SET OF signedAttributes */
5613 localIdx = idx;
5614 if (ret == 0 && GetASNTag(in, &localIdx, &tag, inSz) == 0 &&
5615 tag == (ASN_CONSTRUCTED | ASN_CONTEXT_SPECIFIC | 0)) {
5616 idx++;
5617
5618 if (GetLength(in, &idx, &length, inSz) < 0)
5619 ret = ASN_PARSE_E;
5620
5621 /* save pointer and length */
5622 *signedAttrib = &in[idx];
5623 *signedAttribSz = length;
5624
5625 if (ret == 0 && wc_PKCS7_ParseAttribs(pkcs7, *signedAttrib,
5626 *signedAttribSz) < 0) {
5627 WOLFSSL_MSG("Error parsing signed attributes");
5628 ret = ASN_PARSE_E;
5629 }
5630
5631 idx += (word32)length;
5632 }
5633
5634 /* Get digestEncryptionAlgorithm (signatureAlgorithm) - parse manually
5635 * so we can decode id-RSASSA-PSS parameters in all builds. */
5636#if defined(WC_RSA_PSS) && !defined(NO_RSA)
5637 pkcs7->pssParamsPresent = 0;
5638#endif
5639 if (ret == 0) {
5640 int algoSeqLen = 0;
5641 word32 algoContentStart = 0;
5642 if (GetSequence(in, &idx, &algoSeqLen, (word32)inSz) < 0) {
5643 ret = ASN_PARSE_E;
5644 }
5645 else {
5646 algoContentStart = idx; /* first byte of AlgorithmIdentifier content */
5647 if (GetObjectId(in, &idx, &sigOID, oidSigType, inSz) < 0) {
5648 ret = ASN_PARSE_E;
5649 }
5650 /* Only parse params when still inside the AlgorithmIdentifier;
5651 * when optional params are absent, idx is already past the sequence. */
5652 else if (algoContentStart + (word32)algoSeqLen > idx) {
5653#if defined(WC_RSA_PSS) && !defined(NO_RSA)
5654 word32 paramsStart = idx;
5655#endif
5656 byte paramTag;
5657 int paramLen = 0;
5658 if (GetASNTag(in, &idx, ¶mTag, inSz) != 0 ||
5659 GetLength(in, &idx, ¶mLen, inSz) < 0) {
5660 ret = ASN_PARSE_E;
5661 }
5662 else {
5663#if defined(WC_RSA_PSS) && !defined(NO_RSA)
5664 if ((word32)sigOID == (word32)CTC_RSASSAPSS &&
5665 paramTag == (ASN_SEQUENCE | ASN_CONSTRUCTED)) {
5666 word32 tlvLen = (idx - paramsStart) +
5667 (word32)paramLen;
5668 enum wc_HashType pssHash = WC_HASH_TYPE_SHA;
5669 int pssMgfVal = 0, pssSalt = 0;
5670 if (paramsStart + tlvLen > (word32)inSz) {
5671 return ASN_PARSE_E;
5672 }
5673 ret = wc_DecodeRsaPssParams(in + paramsStart, tlvLen,
5674 &pssHash, &pssMgfVal,
5675 &pssSalt);
5676 if (ret == 0) {
5677 pkcs7->pssSaltLen = pssSalt;
5678 pkcs7->pssHashType = (int)pssHash;
5679 pkcs7->pssMgf = pssMgfVal;
5680 pkcs7->pssParamsPresent = 1;
5681 }
5682 else {
5683 WOLFSSL_MSG("RSASSA-PSS parameters invalid - failing parse");
5684 return ASN_PARSE_E;
5685 }
5686 }
5687#endif
5688 idx += (word32)paramLen;
5689 }
5690 }
5691 }
5692 }
5693
5694 /* store public key type based on digestEncryptionAlgorithm */
5695 if (ret == 0) {
5696 ret = wc_PKCS7_SetPublicKeyOID(pkcs7, (int)sigOID);
5697 if (ret < 0) {
5698 WOLFSSL_MSG("Failed to set public key OID from signature");
5699 }
5700 else {
5701 /* if previous return was positive then was success */
5702 ret = 0;
5703 }
5704 }
5705 }
5706
5707 /* update index on success */
5708 if (ret == 0) {
5709 *idxIn = idx;
5710 }
5711
5712 return ret;
5713}
5714
5715/* parse input to get single/multiple octet strings.
5716 * get each octet string from stream up to the size defined by
5717 * MAX_PKCS7_STREAM_BUFFER then hash and store them to the content buffer.
5718 * hash is stored to pkcs7->stream->hashBuf and its size in
5719 * pkcs7->stream->hashBufSz if keepContent is true, accumulates content into
5720 * pkcs7->stream->content and stores its size in pkcs7->stream->contentSz.
5721 */
5722#ifndef NO_PKCS7_STREAM
5723static int wc_PKCS7_HandleOctetStrings(wc_PKCS7* pkcs7, byte* in, word32 inSz,
5724 word32* tmpIdx, word32* idx, int keepContent)
5725{
5726 int ret, length = 0;
5727 word32 msgSz, i, contBufSz;
5728 byte tag;
5729 byte* msg = NULL;
5730 byte* tempBuf = NULL;
5731
5732 /* allow 0 for inSz in streaming */
5733 if (inSz == 0) {
5734 return WC_PKCS7_WANT_READ_E;
5735 }
5736
5737 if (pkcs7 == NULL || in == NULL || idx == NULL)
5738 return BAD_FUNC_ARG;
5739
5740 /* no content case, do nothing */
5741 if (pkcs7->stream->noContent) {
5742 if (pkcs7->content && pkcs7->contentSz > 0) {
5743 XFREE(pkcs7->stream->content, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
5744 pkcs7->stream->content = NULL;
5745
5746 pkcs7->stream->content = (byte*)XMALLOC(pkcs7->contentSz,
5747 pkcs7->heap, DYNAMIC_TYPE_PKCS7);
5748 if (pkcs7->stream->content == NULL) {
5749 WOLFSSL_MSG("Failed to grow content buffer.");
5750 return MEMORY_E;
5751 }
5752 XMEMCPY(pkcs7->stream->content, pkcs7->content, pkcs7->contentSz);
5753 pkcs7->stream->contentSz = pkcs7->contentSz;
5754 }
5755 return 0;
5756 }
5757
5758 /* free pkcs7->contentDynamic buffer */
5759 XFREE(pkcs7->contentDynamic, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
5760 pkcs7->contentDynamic = NULL;
5761
5762 while(1) {
5763 if ((ret = wc_PKCS7_AddDataToStream(pkcs7, in, inSz,
5764 pkcs7->stream->expected, &msg, idx)) != 0) {
5765 break;
5766 }
5767
5768 msgSz = (pkcs7->stream->length > 0)? pkcs7->stream->length:inSz;
5769
5770 if (pkcs7->stream->currContRmnSz == 0) {
5771
5772 /* processed single OCTET STRING, try to find another one. */
5773 if ((ret = GetASNTag(msg, idx, &tag, msgSz)) < 0) {
5774 break;
5775 }
5776
5777 /* if another OCTET STRING is found, get its length */
5778 if (ret == 0 && tag == ASN_OCTET_STRING) {
5779
5780 if (ret == 0 && GetLength_ex(msg, idx, &length, msgSz,
5781 NO_USER_CHECK) < 0){
5782 ret = ASN_PARSE_E;
5783 break;
5784 }
5785
5786 /* set up for next octet string */
5787 pkcs7->stream->currContSz = (word32)length;
5788 pkcs7->stream->currContRmnSz = (word32)length;
5789 pkcs7->stream->expected = min(pkcs7->stream->currContRmnSz,
5790 MAX_PKCS7_STREAM_BUFFER);
5791
5792 /* advance read index */
5793 if (wc_PKCS7_StreamEndCase(pkcs7, tmpIdx, idx) != 0) {
5794 break;
5795 }
5796
5797 /* check if expected data is available in stream */
5798 ret = wc_PKCS7_AddDataToStream(pkcs7, in, inSz,
5799 pkcs7->stream->expected, &msg, idx);
5800 if (ret == WC_NO_ERR_TRACE(WC_PKCS7_WANT_READ_E)) {
5801 break; /* ask user more input */
5802 }
5803
5804 /* data available, continue processing */
5805 continue;
5806 }
5807 /* reached to the end of contents. trailing zeros may follow. */
5808 else if (ret == 0 && tag == ASN_EOC) {
5809
5810 /* ASN_EOC tag and one zero follows to show the end of
5811 * in-definite length encoding.
5812 * number of indef is stored in pkcs7->stream->cntIdfCnt.
5813 */
5814 pkcs7->stream->expected = (word32)(ASN_TAG_SZ + TRAILING_ZERO) *
5815 (word32)pkcs7->stream->cntIdfCnt;
5816
5817 /* dec idx by one since already consumed to get ASN_EOC */
5818 (*idx)--;
5819
5820 if (wc_PKCS7_StreamEndCase(pkcs7, tmpIdx, idx) != 0) {
5821 break;
5822 }
5823
5824 /* check if expected data is available in stream */
5825 ret = wc_PKCS7_AddDataToStream(pkcs7, in, inSz,
5826 pkcs7->stream->expected, &msg, idx);
5827 if (ret == WC_NO_ERR_TRACE(WC_PKCS7_WANT_READ_E)) {
5828 break; /* ask user more input */
5829 }
5830
5831 /* data available, continue processing trailing zeros */
5832 for (i = 0; i < pkcs7->stream->expected; i++) {
5833 if (msg[*idx + i] != 0) {
5834 ret = ASN_PARSE_E;
5835 break;
5836 }
5837 }
5838 /* reset indef-length count */
5839 pkcs7->stream->cntIdfCnt = 0;
5840
5841 /* advance read index */
5842 *idx += pkcs7->stream->expected;
5843
5844 if (wc_PKCS7_StreamEndCase(pkcs7, tmpIdx, idx) != 0) {
5845 break;
5846 }
5847
5848 /* handled OCTET STRINGs successfully */
5849 ret = 0;
5850 break;
5851 }
5852 /* reached to the end of contents without trailing zeros */
5853 else if (ret == 0) {
5854
5855 /* dec idx by one since already consumed to get ASN_EOC */
5856 (*idx)--;
5857
5858 if (wc_PKCS7_StreamEndCase(pkcs7, tmpIdx, idx) != 0) {
5859 break;
5860 }
5861
5862 ret = wc_PKCS7_AddDataToStream(pkcs7, in, inSz,
5863 pkcs7->stream->expected, &msg, idx);
5864 if (ret == WC_NO_ERR_TRACE(WC_PKCS7_WANT_READ_E)) {
5865 break;
5866 }
5867
5868 /* handled OCTET STRINGs successfully */
5869 ret = 0;
5870 break;
5871 }
5872 else {
5873 break;
5874 }
5875 }
5876 else {
5877 /* got partial octet string data */
5878 /* accumulate partial octet string to buffer */
5879 if (keepContent) {
5880 #ifdef ASN_BER_TO_DER
5881 if (pkcs7->streamOutCb) {
5882 ret = wc_HashUpdate(&pkcs7->stream->hashAlg,
5883 pkcs7->stream->hashType,
5884 msg + *idx, pkcs7->stream->expected);
5885 if (ret != 0)
5886 break;
5887 pkcs7->streamOutCb(pkcs7, msg + *idx,
5888 pkcs7->stream->expected, pkcs7->streamCtx);
5889 }
5890 else
5891 #endif /* ASN_BER_TO_DER */
5892 {
5893 /* store current content buffer temporarily */
5894 tempBuf = pkcs7->stream->content;
5895 pkcs7->stream->content = NULL;
5896
5897 /* grow content buffer */
5898 contBufSz = pkcs7->stream->accumContSz;
5899 pkcs7->stream->accumContSz += pkcs7->stream->expected;
5900
5901 pkcs7->stream->content =
5902 (byte*)XMALLOC(pkcs7->stream->accumContSz,
5903 pkcs7->heap, DYNAMIC_TYPE_PKCS7);
5904
5905 if (pkcs7->stream->content == NULL) {
5906 WOLFSSL_MSG("failed to grow content buffer.");
5907 if (tempBuf != NULL) {
5908 XFREE(tempBuf, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
5909 }
5910 ret = MEMORY_E;
5911 break;
5912 }
5913 else {
5914 /* accumulate content */
5915 if (tempBuf != NULL && contBufSz != 0) {
5916 XMEMCPY(pkcs7->stream->content, tempBuf, contBufSz);
5917 }
5918 XMEMCPY(pkcs7->stream->content + contBufSz, msg + *idx,
5919 pkcs7->stream->expected);
5920 if (tempBuf != NULL) {
5921 XFREE(tempBuf, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
5922 }
5923 }
5924 }
5925 }
5926
5927 *idx += pkcs7->stream->expected;
5928 pkcs7->stream->currContRmnSz -= pkcs7->stream->expected;
5929 pkcs7->stream->contentSz += pkcs7->stream->expected;
5930
5931 if (wc_PKCS7_StreamEndCase(pkcs7, tmpIdx, idx) != 0) {
5932 break;
5933 }
5934
5935 if (pkcs7->stream->currContRmnSz > 0) {
5936 pkcs7->stream->expected = min(pkcs7->stream->currContRmnSz,
5937 MAX_PKCS7_STREAM_BUFFER);
5938 }
5939 else {
5940 /* Processed current OCTET STRING. Proceed to the next one. */
5941 pkcs7->stream->currContRmnSz = 0;
5942 pkcs7->stream->currContSz = 0;
5943 pkcs7->stream->expected= ASN_TAG_SZ + MAX_LENGTH_SZ;
5944
5945 if (pkcs7->stream->maxLen > 0 &&
5946 (pkcs7->stream->maxLen - pkcs7->stream->totalRd)
5947 < ASN_TAG_SZ + MAX_LENGTH_SZ) {
5948 /* seems reached to end of content */
5949 ret = 0;
5950 break;
5951 }
5952 }
5953
5954 /* data available */
5955 continue;
5956 }
5957 }
5958 return ret;
5959}
5960#endif /* !NO_PKCS7_STREAM */
5961/* Finds the certificates in the message and saves it. By default allows
5962 * degenerate cases which can have no signer.
5963 *
5964 * By default expects type SIGNED_DATA (SignedData) which can have any number of
5965 * elements in signerInfos collection, including zero. (RFC2315 section 9.1)
5966 * When adding support for the case of SignedAndEnvelopedData content types a
5967 * signer is required. In this case the PKCS7 flag noDegenerate could be set.
5968 */
5969static int PKCS7_VerifySignedData(wc_PKCS7* pkcs7, const byte* hashBuf,
5970 word32 hashSz, byte* in, word32 inSz,
5971 byte* in2, word32 in2Sz)
5972{
5973 word32 idx, maxIdx = inSz, outerContentType = 0, contentTypeSz = 0, totalSz = 0;
5974 int length = 0, version = 0, ret = 0;
5975 byte* content = NULL;
5976 byte* contentDynamic = NULL;
5977 byte* sig = NULL;
5978 byte* cert = NULL;
5979 byte* signedAttrib = NULL;
5980 byte* contentType = NULL;
5981 int encapContentInfoLen = 0;
5982 int contentSz = 0, sigSz = 0, certSz = 0, signedAttribSz = 0;
5983 word32 localIdx, start;
5984 word32 certIdx, certIdx2;
5985 byte degenerate = 0;
5986 byte detached = 0;
5987 byte tag = 0;
5988 word16 contentIsPkcs7Type = 0;
5989#ifdef ASN_BER_TO_DER
5990 byte* der;
5991#endif
5992 int multiPart = 0, keepContent;
5993 int contentLen = 0;
5994
5995 byte* pkiMsg = in;
5996 word32 pkiMsgSz = inSz;
5997#ifndef NO_PKCS7_STREAM
5998 word32 stateIdx = 0;
5999 word32 hashOID = 0;
6000 enum wc_HashType hashType = WC_HASH_TYPE_NONE;
6001 byte* src = NULL;
6002 word32 srcSz;
6003#endif
6004 byte* pkiMsg2 = in2;
6005 word32 pkiMsg2Sz = in2Sz;
6006 (void)keepContent;
6007 if (pkcs7 == NULL)
6008 return BAD_FUNC_ARG;
6009
6010#ifndef NO_PKCS7_STREAM
6011 /* allow for 0 size inputs with stream mode */
6012 if (pkiMsg == NULL && pkiMsgSz > 0)
6013 return BAD_FUNC_ARG;
6014
6015#else
6016 if (pkiMsg == NULL || pkiMsgSz == 0)
6017 return BAD_FUNC_ARG;
6018#endif
6019
6020 if ((hashSz > 0 && hashBuf == NULL) || (pkiMsg2Sz > 0 && pkiMsg2 == NULL)) {
6021 return BAD_FUNC_ARG;
6022 }
6023 idx = 0;
6024
6025#ifdef ASN_BER_TO_DER
6026 if (pkcs7->derSz > 0 && pkcs7->der) {
6027 pkiMsg = pkcs7->der;
6028 }
6029#endif
6030
6031#ifndef NO_PKCS7_STREAM
6032 if (pkcs7->stream == NULL) {
6033 if ((ret = wc_PKCS7_CreateStream(pkcs7)) != 0) {
6034 return ret;
6035 }
6036 }
6037#endif
6038
6039 switch (pkcs7->state) {
6040 case WC_PKCS7_START:
6041 #ifndef NO_PKCS7_STREAM
6042 /* The expected size calculation originally assumed digest OID
6043 * with NULL params, -2 to also accept with absent params */
6044 if ((ret = wc_PKCS7_AddDataToStream(pkcs7, in, inSz, (MAX_SEQ_SZ +
6045 MAX_VERSION_SZ + MAX_SEQ_SZ + MAX_LENGTH_SZ +
6046 ASN_TAG_SZ + MAX_OID_SZ + MAX_SEQ_SZ) - 2,
6047 &pkiMsg, &idx)) != 0) {
6048 break;
6049 }
6050
6051 pkiMsgSz = (pkcs7->stream->length > 0)? pkcs7->stream->length: inSz;
6052
6053 /* get content info size */
6054 localIdx = 0;
6055 if (GetSequence_ex(pkiMsg, &localIdx, &length, pkiMsgSz,
6056 NO_USER_CHECK) < 0) {
6057 break;
6058 }
6059 if (ret == 0 && length > 0)
6060 pkcs7->stream->maxLen = (word32)length + localIdx;
6061 else
6062 pkcs7->stream->maxLen = inSz;
6063
6064 #endif
6065
6066 /* determine total message size */
6067 totalSz = pkiMsgSz;
6068 if (pkiMsg2 && pkiMsg2Sz > 0) {
6069 totalSz += pkiMsg2Sz + pkcs7->contentSz;
6070 }
6071
6072 /* Get the contentInfo sequence */
6073 if (ret == 0 && GetSequence_ex(pkiMsg, &idx, &length, totalSz,
6074 NO_USER_CHECK) < 0)
6075 ret = ASN_PARSE_E;
6076
6077 if (ret == 0 && length == 0 && pkiMsg[idx-1] == ASN_INDEF_LENGTH) {
6078
6079 #if defined(NO_PKCS7_STREAM)
6080 #ifdef ASN_BER_TO_DER
6081 word32 len = 0;
6082
6083 ret = wc_BerToDer(pkiMsg, pkiMsgSz, NULL, &len);
6084 if (ret != WC_NO_ERR_TRACE(LENGTH_ONLY_E))
6085 return ret;
6086 pkcs7->der = (byte*)XMALLOC(len, pkcs7->heap,
6087 DYNAMIC_TYPE_PKCS7);
6088 if (pkcs7->der == NULL)
6089 return MEMORY_E;
6090 ret = wc_BerToDer(pkiMsg, pkiMsgSz, pkcs7->der, &len);
6091 if (ret < 0)
6092 return ret;
6093
6094 pkiMsg = in = pkcs7->der;
6095 inSz = pkcs7->derSz = len;
6096 idx = 0;
6097 #ifdef NO_PKCS7_STREAM
6098 pkiMsgSz = len;
6099 #else
6100 wc_PKCS7_ResetStream(pkcs7);
6101 if ((ret = wc_PKCS7_AddDataToStream(pkcs7, in, inSz,
6102 MAX_SEQ_SZ + MAX_VERSION_SZ + MAX_SEQ_SZ +
6103 MAX_LENGTH_SZ + ASN_TAG_SZ + MAX_OID_SZ +
6104 MAX_SEQ_SZ, &pkiMsg, &idx)) != 0) {
6105 break;
6106 }
6107
6108 pkiMsgSz = (pkcs7->stream->length > 0)? pkcs7->stream->length:
6109 inSz;
6110
6111 totalSz = pkiMsgSz;
6112 if (pkiMsg2 && pkiMsg2Sz > 0) {
6113 totalSz += pkiMsg2Sz + pkcs7->contentSz;
6114 }
6115
6116 if ((ret = wc_PKCS7_SetMaxStream(pkcs7, in, len)) != 0) {
6117 break;
6118 }
6119 #endif
6120 if (GetSequence_ex(pkiMsg, &idx, &length, pkiMsgSz,
6121 NO_USER_CHECK) < 0)
6122 return ASN_PARSE_E;
6123 #else
6124 ret = BER_INDEF_E;
6125 #endif
6126 #else
6127 /* the bundle has indefinite length encoding */
6128 pkcs7->stream->indefLen = 1;
6129
6130 #endif /* NO_PKCS7_STREAM */
6131 }
6132
6133 /* Get the contentInfo contentType */
6134 if (ret == 0 && wc_GetContentType(pkiMsg, &idx, &outerContentType,
6135 pkiMsgSz) < 0)
6136 ret = ASN_PARSE_E;
6137
6138 if (ret == 0 && outerContentType != SIGNED_DATA) {
6139 WOLFSSL_MSG("PKCS#7 input not of type SignedData");
6140 ret = PKCS7_OID_E;
6141 }
6142
6143 /* get the ContentInfo content */
6144 if (ret == 0 && GetASNTag(pkiMsg, &idx, &tag, totalSz) != 0)
6145 ret = ASN_PARSE_E;
6146
6147 if (ret == 0 && tag != (ASN_CONSTRUCTED | ASN_CONTEXT_SPECIFIC | 0))
6148 ret = ASN_PARSE_E;
6149
6150 if (ret == 0 && GetLength_ex(pkiMsg, &idx, &length, totalSz,
6151 NO_USER_CHECK) < 0)
6152 ret = ASN_PARSE_E;
6153
6154 /* Get the signedData sequence */
6155 if (ret == 0 && GetSequence_ex(pkiMsg, &idx, &length, totalSz,
6156 NO_USER_CHECK) < 0)
6157 ret = ASN_PARSE_E;
6158
6159 /* Get the version */
6160 if (ret == 0 && GetMyVersion(pkiMsg, &idx, &version, pkiMsgSz) < 0)
6161 ret = ASN_PARSE_E;
6162
6163 /* version 1 follows RFC 2315 */
6164 /* version 3 follows RFC 4108 */
6165 if (ret == 0 && (version != 1 && version != 3)) {
6166 WOLFSSL_MSG("PKCS#7 signedData needs to be version 1 or 3");
6167 ret = ASN_VERSION_E;
6168 }
6169 pkcs7->version = (byte)version;
6170
6171 /* Get the set of DigestAlgorithmIdentifiers */
6172 if (ret == 0 && GetSet(pkiMsg, &idx, &length, pkiMsgSz) < 0)
6173 ret = ASN_PARSE_E;
6174
6175 localIdx = idx;
6176
6177 #ifndef NO_PKCS7_STREAM
6178 /* initialize hashType*/
6179 pkcs7->stream->hashType = WC_HASH_TYPE_NONE;
6180
6181 /* Get the first DigestAlgorithmIdentifier from the SET */
6182 if (ret == 0 && length > 0) {
6183 if (GetAlgoId(pkiMsg, &idx, &hashOID, oidHashType, pkiMsgSz)
6184 < 0)
6185 ret = ASN_PARSE_E;
6186
6187 pkcs7->hashOID = (int)hashOID;
6188 /* get hash type */
6189 hashType = wc_OidGetHash(pkcs7->hashOID);
6190
6191 if (hashType == WC_HASH_TYPE_NONE) {
6192 WOLFSSL_MSG("Error getting hash type for PKCS7 content"
6193 " verification");
6194 ret = ASN_PARSE_E;
6195 }
6196 if (wc_HashGetDigestSize(hashType) < 0) {
6197 WOLFSSL_MSG("Error getting digest size");
6198 ret = ASN_PARSE_E;
6199 }
6200 /* store hashType for later hashing */
6201 pkcs7->stream->hashType = hashType;
6202
6203 /* restore idx */
6204 idx = localIdx;
6205
6206 WOLFSSL_MSG("DigestAlgorithmIdentifier found in bundle");
6207 }
6208 #endif /* !NO_PKCS7_STREAM */
6209
6210 /* Skip the set. */
6211 idx += (word32)length;
6212 degenerate = (length == 0) ? 1 : 0;
6213 #ifndef NO_PKCS7_STREAM
6214 pkcs7->stream->degenerate = (degenerate != 0);
6215 #endif /* !NO_PKCS7_STREAM */
6216 if (pkcs7->noDegenerate == 1 && degenerate != 0) {
6217 ret = PKCS7_NO_SIGNER_E;
6218 }
6219
6220 if (ret != 0)
6221 break;
6222
6223 #ifndef NO_PKCS7_STREAM
6224 if ((ret = wc_PKCS7_StreamEndCase(pkcs7, &stateIdx, &idx)) != 0) {
6225 break;
6226 }
6227 if (pkiMsg2 && pkiMsg2Sz > 0) {
6228 pkcs7->stream->maxLen += pkiMsg2Sz + pkcs7->contentSz;
6229 }
6230 wc_PKCS7_StreamStoreVar(pkcs7, totalSz, 0, 0);
6231
6232 #endif
6233
6234 wc_PKCS7_ChangeState(pkcs7, WC_PKCS7_VERIFY_STAGE2);
6235
6236 #ifndef NO_PKCS7_STREAM
6237 pkcs7->stream->expected = MAX_SEQ_SZ + MAX_OID_SZ + ASN_TAG_SZ +
6238 MAX_LENGTH_SZ + ASN_TAG_SZ + MAX_LENGTH_SZ;
6239 #endif /* !NO_PKCS7_STREAM */
6240 FALL_THROUGH;
6241
6242 case WC_PKCS7_VERIFY_STAGE2:
6243 #ifndef NO_PKCS7_STREAM
6244 if ((ret = wc_PKCS7_AddDataToStream(pkcs7, in, inSz + in2Sz,
6245 pkcs7->stream->expected, &pkiMsg, &idx)) != 0) {
6246 break;
6247 }
6248 degenerate = pkcs7->stream->degenerate;
6249
6250 wc_PKCS7_StreamGetVar(pkcs7, &totalSz, 0, 0);
6251 if (pkcs7->stream->length > 0)
6252 pkiMsgSz = pkcs7->stream->length;
6253 #ifdef ASN_BER_TO_DER
6254 else if (pkcs7->der)
6255 pkiMsgSz = pkcs7->derSz;
6256 #endif
6257 else
6258 pkiMsgSz = inSz;
6259
6260 #endif
6261 /* Get the inner ContentInfo sequence */
6262 if (GetSequence_ex(pkiMsg, &idx, &encapContentInfoLen, pkiMsgSz,
6263 NO_USER_CHECK) < 0)
6264 ret = ASN_PARSE_E;
6265
6266 /* Get the inner ContentInfo contentType */
6267 if (ret == 0) {
6268 int isIndef = 0;
6269 word32 tmpIdx = idx;
6270 if (encapContentInfoLen == 0 &&
6271 pkiMsg[idx-1] == ASN_INDEF_LENGTH) {
6272 isIndef = 1;
6273 #ifndef NO_PKCS7_STREAM
6274 /* count up indef-length count */
6275 pkcs7->stream->cntIdfCnt++;
6276 #endif
6277 }
6278 if (GetASNObjectId(pkiMsg, &idx, &length, pkiMsgSz) == 0) {
6279 contentType = pkiMsg + tmpIdx;
6280 contentTypeSz = (word32)length + (idx - tmpIdx);
6281 idx += (word32)length;
6282 }
6283 else {
6284 ret = ASN_PARSE_E;
6285 }
6286 /* if indef, skip EOF */
6287 if (isIndef) {
6288 if (idx + 1 >= pkiMsgSz) {
6289 ret = ASN_PARSE_E;
6290 }
6291 else if (pkiMsg[idx] == ASN_EOC && pkiMsg[idx+1] == 0) {
6292 idx += 2; /* skip EOF + zero byte */
6293 #ifndef NO_PKCS7_STREAM
6294 pkcs7->stream->cntIdfCnt--;
6295 #endif
6296 }
6297 }
6298 }
6299
6300 if (ret != 0)
6301 break;
6302
6303 /* Check for content, it could be omitted when degenerate */
6304 localIdx = idx;
6305 ret = 0;
6306 if (localIdx + 1 > pkiMsgSz) {
6307 ret = BUFFER_E;
6308 break;
6309 }
6310
6311 /* Set error state if no more data left in ContentInfo, meaning
6312 * no content - may be detached. Will recover from error below */
6313 if ((encapContentInfoLen != 0) &&
6314 ((word32)encapContentInfoLen - contentTypeSz == 0)) {
6315 ret = ASN_PARSE_E;
6316 #ifndef NO_PKCS7_STREAM
6317 pkcs7->stream->noContent = 1;
6318 #endif
6319 }
6320
6321 /* PKCS#7 spec:
6322 * content [0] EXPLICIT ANY DEFINED BY contentType OPTIONAL
6323 * CMS spec:
6324 * eContent [0] EXPLICIT OCTET STRING OPTIONAL
6325 */
6326 if (ret == 0 && GetASNTag(pkiMsg, &localIdx, &tag, pkiMsgSz) != 0)
6327 ret = ASN_PARSE_E;
6328
6329 if (ret == 0 && tag != (ASN_CONSTRUCTED | ASN_CONTEXT_SPECIFIC | 0))
6330 ret = ASN_PARSE_E;
6331
6332 /* Get length of inner eContent payload. For CMS, spec defines
6333 * OCTET_STRING will be next. If so, we use the length retrieved
6334 * there. PKCS#7 spec defines ANY as eContent type. In this case
6335 * we fall back and save this content length for use later */
6336 if (ret == 0 && localIdx >= pkiMsgSz) {
6337 /* Truncated input: don't dereference past the buffer.
6338 * Break out of the switch directly so the degenerate-
6339 * recovery path below cannot mask this error. */
6340 ret = BUFFER_E;
6341 break;
6342 }
6343
6344 if (ret == 0 && pkiMsg[localIdx] != ASN_INDEF_LENGTH) {
6345 if (GetLength_ex(pkiMsg, &localIdx, &length, pkiMsgSz,
6346 NO_USER_CHECK) <= 0) {
6347 ret = ASN_PARSE_E;
6348 }
6349
6350 if (localIdx >= pkiMsgSz) {
6351 ret = BUFFER_E;
6352 }
6353 }
6354 else if (ret == 0 && pkiMsg[localIdx] == ASN_INDEF_LENGTH) {
6355 #ifndef NO_PKCS7_STREAM
6356 pkcs7->stream->cntIdfCnt++; /* count up indef-length count */
6357 #endif
6358 length = 0;
6359 localIdx++;
6360 }
6361 else {
6362 length = 0;
6363 localIdx++;
6364 }
6365
6366 /* Save idx to back up in case of PKCS#7 eContent */
6367 start = localIdx;
6368
6369 /* get length of content in the case that there is multiple parts */
6370 if (ret == 0 && GetASNTag(pkiMsg, &localIdx, &tag, pkiMsgSz) < 0)
6371 ret = ASN_PARSE_E;
6372
6373 if (ret == 0 &&
6374 (tag != (ASN_OCTET_STRING | ASN_CONSTRUCTED) &&
6375 (tag != ASN_OCTET_STRING))) {
6376
6377 /* If reached end of ContentInfo, or we see the next element
6378 * ([0] IMPLICIT CertificateSet), set error state. Either
6379 * true error or detached */
6380 if (tag == (ASN_CONSTRUCTED | ASN_CONTEXT_SPECIFIC | 0)) {
6381 ret = ASN_PARSE_E;
6382 }
6383
6384 /* Back up before getting tag, process as PKCS#7 ANY and use
6385 * this as start of content. */
6386 localIdx = start;
6387 pkcs7->contentIsPkcs7Type = 1;
6388
6389 #ifndef NO_PKCS7_STREAM
6390 /* Set streaming variables for PKCS#7 type content.
6391 * length contains the size from [0] EXPLICIT wrapper */
6392 pkcs7->stream->multi = 0;
6393 pkcs7->stream->currContIdx = localIdx;
6394 pkcs7->stream->currContSz = (word32)length;
6395 pkcs7->stream->currContRmnSz = (word32)length;
6396 #endif
6397 }
6398 else {
6399 /* CMS eContent OCTET_STRING */
6400 if (ret == 0 && tag == (ASN_OCTET_STRING | ASN_CONSTRUCTED)) {
6401 multiPart = 1;
6402
6403 /* Get length of all OCTET_STRINGs. */
6404 if (GetLength_ex(pkiMsg, &localIdx, &contentLen, pkiMsgSz,
6405 NO_USER_CHECK) < 0)
6406 ret = ASN_PARSE_E;
6407 #ifndef NO_PKCS7_STREAM
6408 if (ret == 0 && pkiMsg[localIdx - 1] == ASN_INDEF_LENGTH) {
6409 pkcs7->stream->cntIdfCnt++; /* indef-length count */
6410 }
6411 #endif
6412 /* Check whether there is one OCTET_STRING inside. */
6413 start = localIdx;
6414 if (localIdx >= pkiMsgSz) {
6415 ret = BUFFER_E;
6416 }
6417
6418 if (ret == 0 && GetASNTag(pkiMsg, &localIdx, &tag, pkiMsgSz)
6419 != 0)
6420 ret = ASN_PARSE_E;
6421
6422 if (ret == 0 && tag != ASN_OCTET_STRING)
6423 ret = ASN_PARSE_E;
6424
6425 if (ret == 0 && GetLength_ex(pkiMsg, &localIdx, &length,
6426 pkiMsgSz, NO_USER_CHECK) < 0)
6427 ret = ASN_PARSE_E;
6428
6429 if (ret == 0) {
6430 /* Use single OCTET_STRING directly, or reset length. */
6431 if (localIdx - start + (word32)length ==
6432 (word32)contentLen) {
6433 multiPart = 0;
6434 } else {
6435 #ifndef NO_PKCS7_STREAM
6436 pkcs7->stream->multi = (multiPart != 0);
6437 pkcs7->stream->currContIdx = localIdx;
6438 pkcs7->stream->currContSz = (word32)length;
6439 pkcs7->stream->currContRmnSz = (word32)length;
6440 #endif
6441 /* reset length to outer OCTET_STRING for bundle
6442 * size check below */
6443 length = contentLen;
6444 }
6445 localIdx = start;
6446 }
6447
6448 if (ret != 0) {
6449 /* failed ASN1 parsing during OCTET_STRING checks */
6450 break;
6451 }
6452 }
6453
6454 /* get length of content in case of single part */
6455 if (ret == 0 && !multiPart) {
6456 if (tag != ASN_OCTET_STRING)
6457 ret = ASN_PARSE_E;
6458
6459 if (ret == 0 && GetLength_ex(pkiMsg, &localIdx,
6460 &length, pkiMsgSz, NO_USER_CHECK) < 0)
6461 ret = ASN_PARSE_E;
6462 #ifndef NO_PKCS7_STREAM
6463 if (ret == 0) {
6464 pkcs7->stream->multi = (multiPart != 0);
6465 pkcs7->stream->currContIdx = localIdx;
6466 pkcs7->stream->currContSz = (word32)length;
6467 pkcs7->stream->currContRmnSz = (word32)length;
6468 }
6469 #endif
6470 }
6471 }
6472
6473 /* update idx if successful */
6474 if (ret == 0) {
6475 /* support using header and footer without content */
6476 if (pkiMsg2 && pkiMsg2Sz > 0 && hashBuf && hashSz > 0) {
6477 localIdx = 0;
6478 #ifndef NO_PKCS7_STREAM
6479 pkcs7->stream->noContent = 1;
6480 #endif
6481
6482 }
6483 idx = localIdx;
6484 }
6485 else {
6486 /* If either pkcs7->content and pkcs7->contentSz are set
6487 * (detached signature where user has set content explicitly
6488 * into pkcs7->content/contentSz) OR pkcs7->hashBuf and
6489 * pkcs7->hashSz are set (user has pre-computed content
6490 * digest and passed in instead of content directly), try to
6491 * process as a detached signature */
6492 if (!degenerate &&
6493 ((pkcs7->content != NULL && pkcs7->contentSz != 0) ||
6494 (hashBuf != NULL && hashSz > 0)) ) {
6495 WOLFSSL_MSG("Trying to process as detached signature");
6496 detached = 1;
6497 }
6498
6499 if (!degenerate && !detached && ret != 0)
6500 break;
6501
6502 /* no content to read */
6503 length = 0;
6504 contentLen = 0;
6505
6506 pkiMsg2 = pkiMsg;
6507 pkiMsg2Sz = pkiMsgSz;
6508
6509 /* reset ret */
6510 ret = 0;
6511 }
6512
6513 #ifndef NO_PKCS7_STREAM
6514 /* save detached flag value */
6515 pkcs7->stream->detached = (detached != 0);
6516
6517 /* save contentType */
6518 pkcs7->stream->nonce = (byte*)XMALLOC(contentTypeSz, pkcs7->heap,
6519 DYNAMIC_TYPE_PKCS7);
6520 if (pkcs7->stream->nonce == NULL) {
6521 ret = MEMORY_E;
6522 break;
6523 }
6524 else {
6525 pkcs7->stream->nonceSz = contentTypeSz;
6526 XMEMCPY(pkcs7->stream->nonce, contentType, contentTypeSz);
6527 }
6528 if (ret < 0)
6529 break;
6530
6531 if (pkcs7->stream->noContent) {
6532 pkcs7->stream->expected = 0;
6533 }
6534 else {
6535 if (multiPart) {
6536 idx = pkcs7->stream->currContIdx;
6537 }
6538 if (in2Sz > 0 && hashSz > 0) {
6539 /* seems no content included */
6540 pkcs7->stream->expected = + ASN_TAG_SZ + MAX_LENGTH_SZ;
6541 }
6542 else {
6543 pkcs7->stream->expected = pkcs7->stream->currContSz;
6544 }
6545 }
6546
6547 if ((ret = wc_PKCS7_StreamEndCase(pkcs7, &stateIdx, &idx)) != 0) {
6548 break;
6549 }
6550 wc_PKCS7_StreamStoreVar(pkcs7, pkiMsg2Sz, (int)localIdx, length);
6551
6552
6553 #endif /* !NO_PKCS7_STREAM */
6554
6555 wc_PKCS7_ChangeState(pkcs7, WC_PKCS7_VERIFY_STAGE3);
6556
6557 #ifndef NO_PKCS7_STREAM
6558 #ifdef ASN_BER_TO_DER
6559 /* setup hash struct for creating hash of content if needed */
6560 if (pkcs7->streamOutCb) {
6561 ret = wc_HashInit_ex(&pkcs7->stream->hashAlg,
6562 pkcs7->stream->hashType, pkcs7->heap, pkcs7->devId);
6563 if (ret != 0)
6564 break;
6565 }
6566 #endif /* ASN_BER_TO_DER */
6567
6568 /* free pkcs7->stream->content buffer */
6569 XFREE(pkcs7->stream->content, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
6570 pkcs7->stream->content = NULL;
6571 #endif /* !NO_PKCS7_STREAM */
6572
6573 FALL_THROUGH;
6574
6575 case WC_PKCS7_VERIFY_STAGE3:
6576 keepContent = !(pkiMsg2 && pkiMsg2Sz > 0 && hashBuf && hashSz > 0);
6577 #ifndef NO_PKCS7_STREAM
6578 ret = wc_PKCS7_HandleOctetStrings(pkcs7, in, inSz,
6579 &stateIdx, &idx, keepContent);
6580 if (ret != 0)
6581 break;
6582
6583 /* copy content to pkcs7->contentDynamic */
6584 if (keepContent && pkcs7->stream->content &&
6585 pkcs7->stream->contentSz > 0) {
6586 pkcs7->contentDynamic = (byte*)XMALLOC(pkcs7->stream->contentSz,
6587 pkcs7->heap, DYNAMIC_TYPE_PKCS7);
6588 if (pkcs7->contentDynamic == NULL) {
6589 ret = MEMORY_E;
6590 break;
6591 }
6592 XMEMCPY(pkcs7->contentDynamic, pkcs7->stream->content,
6593 pkcs7->stream->contentSz);
6594
6595 pkcs7->contentSz = pkcs7->stream->contentSz;
6596 pkcs7->content = pkcs7->contentDynamic;
6597 }
6598
6599 /* check if bundle has more elements or footer, if not, set content
6600 * to pkcs7->content and hash to pkcs7->hash.
6601 *
6602 * NOTE: this check returns success whenever fewer than 6 bytes
6603 * follow the content within the outer ContentInfo, which also
6604 * accepts truncated bundles whose footer was cut short (e.g. a
6605 * lone certificates [0] tag with no length). Distinguishing a
6606 * legitimate degenerate end (such as an empty signerInfos SET
6607 * "31 00") from truncated junk would require peeking at the
6608 * remaining bytes or making stage 4's `expected` window smaller.
6609 */
6610 if (ret == 0 && pkcs7->stream->maxLen > 0 &&
6611 (pkcs7->stream->maxLen - pkcs7->stream->totalRd)
6612 < ASN_TAG_SZ + MAX_LENGTH_SZ) {
6613
6614 ret = 0;
6615 break;
6616 }
6617 /* expect data length to be enough to check set and seq of certs */
6618 pkcs7->stream->expected = (ASN_TAG_SZ + MAX_LENGTH_SZ) * 2;
6619
6620 #else
6621 /* Break out before content because it can be optional in degenerate
6622 * cases. */
6623 if (ret != 0 && !degenerate)
6624 break;
6625
6626 /* get parts of content */
6627 if (ret == 0 && multiPart) {
6628 int i = 0;
6629 keepContent = !(pkiMsg2 && pkiMsg2Sz > 0 && hashBuf &&
6630 hashSz > 0);
6631
6632 if (keepContent) {
6633 /* Create a buffer to hold content of OCTET_STRINGs. */
6634 pkcs7->contentDynamic = (byte*)XMALLOC(contentLen,
6635 pkcs7->heap, DYNAMIC_TYPE_PKCS7);
6636 if (pkcs7->contentDynamic == NULL)
6637 ret = MEMORY_E;
6638 }
6639
6640 start = localIdx;
6641 /* Use the data from each OCTET_STRING. */
6642 while (ret == 0 && localIdx < start + contentLen) {
6643 if (GetASNTag(pkiMsg, &localIdx, &tag, totalSz) < 0)
6644 ret = ASN_PARSE_E;
6645 if (ret == 0 && tag != ASN_OCTET_STRING)
6646 ret = ASN_PARSE_E;
6647
6648 if (ret == 0 && GetLength(pkiMsg, &localIdx, &length,
6649 totalSz) < 0)
6650 ret = ASN_PARSE_E;
6651 if (ret == 0 && length + localIdx > start + contentLen)
6652 ret = ASN_PARSE_E;
6653
6654 if (ret == 0) {
6655 if (keepContent) {
6656 XMEMCPY(pkcs7->contentDynamic + i,
6657 pkiMsg + localIdx, length);
6658 }
6659 i += length;
6660 localIdx += length;
6661 }
6662 }
6663 localIdx = start; /* reset for sanity check, increment later */
6664 length = i;
6665 }
6666
6667 /* Save the inner data as the content. */
6668 if (ret == 0 && length > 0) {
6669 contentSz = length;
6670
6671 /* support using header and footer without content */
6672 if (pkiMsg2 && pkiMsg2Sz > 0 && hashBuf && hashSz > 0) {
6673 /* Content not provided, use provided pkiMsg2 footer */
6674 content = NULL;
6675 localIdx = 0;
6676 if (contentSz != (int)pkcs7->contentSz) {
6677 WOLFSSL_MSG("Data signed does not match contentSz"
6678 " provided");
6679 ret = BUFFER_E;
6680 }
6681 }
6682 else {
6683 if ((word32)length > pkiMsgSz - localIdx) {
6684 ret = BUFFER_E;
6685 }
6686
6687 /* Content pointer for calculating hashes later */
6688 if (ret == 0 && !multiPart) {
6689 content = &pkiMsg[localIdx];
6690 }
6691 if (ret == 0 && multiPart) {
6692 content = pkcs7->contentDynamic;
6693 }
6694
6695 if (ret == 0) {
6696 idx += length;
6697 }
6698
6699 pkiMsg2 = pkiMsg;
6700 pkiMsg2Sz = pkiMsgSz;
6701 }
6702 }
6703 else {
6704 pkiMsg2 = pkiMsg;
6705 pkiMsg2Sz = pkiMsgSz;
6706 }
6707
6708 /* If getting the content info failed with non degenerate then
6709 * return the error case. Otherwise with a degenerate it is ok
6710 * if the content info was omitted */
6711 if (!degenerate && !detached && (ret != 0)) {
6712 break;
6713 }
6714 else {
6715 ret = 0; /* reset ret state on degenerate case */
6716 }
6717
6718 /* save content */
6719 if (detached == 1) {
6720 /* if detached, use content from user in pkcs7 struct */
6721 content = pkcs7->content;
6722 contentSz = pkcs7->contentSz;
6723 }
6724 #endif /* !NO_PKCS7_STREAM */
6725 wc_PKCS7_ChangeState(pkcs7, WC_PKCS7_VERIFY_STAGE4);
6726
6727 FALL_THROUGH;
6728
6729 case WC_PKCS7_VERIFY_STAGE4:
6730 #ifndef NO_PKCS7_STREAM
6731 if (in2 && in2Sz > 0) {
6732 src = in2;
6733 srcSz = in2Sz;
6734 pkiMsg2 = in2;
6735 }
6736 else {
6737 src = in;
6738 srcSz = inSz;
6739 pkiMsg2 = in;
6740 }
6741 if ((ret = wc_PKCS7_AddDataToStream(pkcs7, src, srcSz,
6742 pkcs7->stream->expected, &pkiMsg2, &idx)) != 0) {
6743 break;
6744 }
6745
6746 #ifdef ASN_BER_TO_DER
6747 if (pkcs7->derSz != 0)
6748 pkiMsg2Sz = pkcs7->derSz;
6749 else
6750 #endif
6751 pkiMsg2Sz = (pkcs7->stream->length > 0)? pkcs7->stream->length:
6752 srcSz;
6753
6754 if (pkcs7->stream->length > 0) {
6755 localIdx = 0;
6756 }
6757
6758 maxIdx = idx + pkcs7->stream->expected;
6759 #endif /* !NO_PKCS7_STREAM */
6760
6761 if (pkiMsg2 == NULL || pkiMsg2Sz == 0) {
6762 pkiMsg2Sz = pkiMsgSz;
6763 pkiMsg2 = pkiMsg;
6764 }
6765
6766 /* Certificates begin "footer" section (ie pkiMsg2) if being used */
6767 /* Get the implicit[0] set of certificates */
6768 if (ret == 0 && idx >= pkiMsg2Sz)
6769 ret = BUFFER_E;
6770
6771 length = 0; /* set length to 0 to check if reading in any certs */
6772 localIdx = idx;
6773
6774 if (ret == 0 && GetASNTag(pkiMsg2, &localIdx, &tag, pkiMsg2Sz) == 0
6775 && tag == (ASN_CONSTRUCTED | ASN_CONTEXT_SPECIFIC | 0)) {
6776 idx++;
6777
6778 if (localIdx >= pkiMsg2Sz) {
6779 ret = BUFFER_E;
6780 }
6781
6782 /* if certificates set has indefinite length, try to get
6783 * the first certificate length of the set.
6784 */
6785 if (ret == 0 && pkiMsg2[localIdx] == ASN_INDEF_LENGTH) {
6786
6787 localIdx++;
6788 certIdx = localIdx;
6789 #ifndef NO_PKCS7_STREAM
6790 /* set indef-length count. used for skipping trailing zeros */
6791 pkcs7->stream->cntIdfCnt = 1;
6792 #endif
6793 ret = GetASNTag(pkiMsg2, &localIdx, &tag, pkiMsg2Sz);
6794 if (ret == 0 && tag == (ASN_CONSTRUCTED | ASN_SEQUENCE)) {
6795 if (GetLength_ex(pkiMsg2, &localIdx, &length, maxIdx,
6796 NO_USER_CHECK) < 0)
6797 ret = ASN_PARSE_E;
6798
6799 WOLFSSL_MSG("certificate set found");
6800
6801 /* adjust cert length */
6802 length += (int)(localIdx - certIdx);
6803 idx = certIdx;
6804 }
6805 }
6806 /* in case certificates set has definite length */
6807 else {
6808
6809 if (GetLength_ex(pkiMsg2, &localIdx, &length, maxIdx,
6810 NO_USER_CHECK) < 0)
6811 ret = ASN_PARSE_E;
6812
6813 idx = localIdx;
6814 }
6815 }
6816
6817 if (ret != 0) {
6818 break;
6819 }
6820 #ifndef NO_PKCS7_STREAM
6821 if (in2 && in2Sz > 0 && hashBuf && hashSz > 0) {
6822 stateIdx = idx; /* case where all data was read from in2 */
6823 }
6824
6825 if ((ret = wc_PKCS7_StreamEndCase(pkcs7, &stateIdx, &idx)) != 0) {
6826 break;
6827 }
6828 wc_PKCS7_StreamStoreVar(pkcs7, pkiMsg2Sz, 0, length);
6829 if (length > 0) {
6830 pkcs7->stream->expected = (word32)length;
6831 }
6832 else {
6833 pkcs7->stream->expected = MAX_SEQ_SZ;
6834 if (pkcs7->stream->expected > (pkcs7->stream->maxLen -
6835 pkcs7->stream->totalRd) + pkcs7->stream->length) {
6836 pkcs7->stream->expected = (pkcs7->stream->maxLen -
6837 pkcs7->stream->totalRd) + pkcs7->stream->length;
6838 }
6839 }
6840 #endif
6841 wc_PKCS7_ChangeState(pkcs7, WC_PKCS7_VERIFY_STAGE5);
6842 FALL_THROUGH;
6843
6844 case WC_PKCS7_VERIFY_STAGE5:
6845 #ifndef NO_PKCS7_STREAM
6846 if (in2 && in2Sz > 0) {
6847 src = in2;
6848 srcSz = in2Sz;
6849 pkiMsg2 = in2;
6850 }
6851 else {
6852 src = in;
6853 srcSz = inSz;
6854 pkiMsg2 = in;
6855 }
6856
6857 if ((ret = wc_PKCS7_AddDataToStream(pkcs7, src, srcSz,
6858 pkcs7->stream->expected, &pkiMsg2, &idx)) != 0) {
6859 break;
6860 }
6861 pkiMsg2Sz = (pkcs7->stream->length > 0)? pkcs7->stream->length:
6862 srcSz;
6863
6864 wc_PKCS7_StreamGetVar(pkcs7, &pkiMsg2Sz, 0, &length);
6865
6866 /* restore content */
6867 content = pkcs7->stream->content;
6868 contentSz = (int)pkcs7->stream->contentSz;
6869
6870 /* restore detached flag */
6871 detached = pkcs7->stream->detached;
6872
6873 /* store current index to get the signerInfo index later */
6874 certIdx2 = idx;
6875 /* store certificate if needed */
6876 if (length > 0 && in2Sz == 0) {
6877 /* free tmpCert if not NULL */
6878 XFREE(pkcs7->stream->tmpCert, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
6879 pkcs7->stream->tmpCert = (byte*)XMALLOC((word32)length,
6880 pkcs7->heap, DYNAMIC_TYPE_PKCS7);
6881 if ((pkiMsg2 == NULL) || (pkcs7->stream->tmpCert == NULL)) {
6882 ret = MEMORY_E;
6883 break;
6884 }
6885 XMEMCPY(pkcs7->stream->tmpCert, pkiMsg2 + idx, (word32)length);
6886 pkiMsg2 = pkcs7->stream->tmpCert;
6887 pkiMsg2Sz = (word32)length;
6888 idx = 0;
6889 }
6890 #else
6891 /* store current index to get the signerInfo index later */
6892 certIdx2 = idx;
6893 #endif
6894
6895 if (length > 0) {
6896 /* At this point, idx is at the first certificate in
6897 * a set of certificates. There may be more than one,
6898 * or none, or they may be a PKCS 6 extended
6899 * certificate. We want to save the first cert if it
6900 * is X.509. */
6901
6902 certIdx = idx;
6903
6904 if (length < MAX_LENGTH_SZ + ASN_TAG_SZ)
6905 ret = BUFFER_E;
6906
6907 if (ret == 0)
6908 ret = GetASNTag(pkiMsg2, &certIdx, &tag, pkiMsg2Sz);
6909
6910 if (ret == 0 && tag == (ASN_CONSTRUCTED | ASN_SEQUENCE)) {
6911 if (GetLength_ex(pkiMsg2, &certIdx, &certSz, pkiMsg2Sz,
6912 NO_USER_CHECK) < 0)
6913 ret = ASN_PARSE_E;
6914
6915 cert = &pkiMsg2[idx];
6916 certSz += (int)(certIdx - idx);
6917 if (certSz > length) {
6918 ret = BUFFER_E;
6919 break;
6920 }
6921 }
6922 #ifdef ASN_BER_TO_DER
6923 der = pkcs7->der;
6924 pkcs7->der = NULL;
6925 #endif
6926 version = pkcs7->version;
6927 contentIsPkcs7Type = pkcs7->contentIsPkcs7Type;
6928
6929 if (ret == 0) {
6930 byte isDynamic = (byte)pkcs7->isDynamic;
6931 #ifndef NO_PKCS7_STREAM
6932 PKCS7State* stream = pkcs7->stream;
6933 pkcs7->stream = NULL;
6934 #endif
6935
6936 /* Save dynamic content before freeing PKCS7 struct */
6937 if (pkcs7->contentDynamic != NULL) {
6938 contentDynamic = (byte*)XMALLOC((word32)contentSz,
6939 pkcs7->heap, DYNAMIC_TYPE_PKCS7);
6940 if (contentDynamic == NULL) {
6941 #ifndef NO_PKCS7_STREAM
6942 pkcs7->stream = stream;
6943 #endif
6944 ret = MEMORY_E;
6945 break;
6946 }
6947 XMEMCPY(contentDynamic, pkcs7->contentDynamic,
6948 (word32)contentSz);
6949 }
6950
6951 /* Free pkcs7 resources but not the structure itself */
6952 pkcs7->isDynamic = 0;
6953 wc_PKCS7_Free(pkcs7);
6954 pkcs7->isDynamic = (isDynamic != 0);
6955 /* This will reset PKCS7 structure and then set the
6956 * certificate */
6957 ret = wc_PKCS7_InitWithCert(pkcs7, cert, (word32)certSz);
6958
6959 /* Restore pkcs7->contentDynamic from above, will be
6960 * freed by application with wc_PKCS7_Free() */
6961 if (contentDynamic != NULL) {
6962 pkcs7->contentDynamic = contentDynamic;
6963 contentDynamic = NULL;
6964 }
6965
6966 /* Restore content is PKCS#7 flag */
6967 pkcs7->contentIsPkcs7Type = (contentIsPkcs7Type != 0);
6968
6969 #ifndef NO_PKCS7_STREAM
6970 pkcs7->stream = stream;
6971 #endif
6972 }
6973 pkcs7->version = (byte)version;
6974 #ifdef ASN_BER_TO_DER
6975 pkcs7->der = der;
6976 #endif
6977 if (ret != 0)
6978 break;
6979
6980 /* iterate through any additional certificates */
6981 if (ret == 0 && MAX_PKCS7_CERTS > 0) {
6982 int sz = 0;
6983 int i;
6984
6985 pkcs7->cert[0] = cert;
6986 pkcs7->certSz[0] = (word32)certSz;
6987 certIdx = idx + (word32)certSz;
6988
6989 for (i = 1; i < MAX_PKCS7_CERTS &&
6990 certIdx + 1 < pkiMsg2Sz &&
6991 certIdx + 1 < (word32)length; i++) {
6992 localIdx = certIdx;
6993
6994 if (ret == 0 && GetASNTag(pkiMsg2, &certIdx, &tag,
6995 pkiMsg2Sz) < 0) {
6996 ret = ASN_PARSE_E;
6997 break;
6998 }
6999
7000 if (ret == 0 &&
7001 tag == (ASN_CONSTRUCTED | ASN_SEQUENCE)) {
7002 if (GetLength(pkiMsg2, &certIdx, &sz,
7003 pkiMsg2Sz) < 0) {
7004 ret = ASN_PARSE_E;
7005 break;
7006 }
7007
7008 pkcs7->cert[i] = &pkiMsg2[localIdx];
7009 pkcs7->certSz[i] = (word32)sz +
7010 (certIdx - localIdx);
7011 certIdx += (word32)sz;
7012 }
7013 }
7014 }
7015 }
7016 idx += (word32)length;
7017
7018 if (!detached) {
7019 /* set content and size after init of PKCS7 structure */
7020 pkcs7->content = content;
7021 pkcs7->contentSz = (word32)contentSz;
7022 }
7023
7024 idx = certIdx2 + (word32)length;
7025
7026 if (ret != 0) {
7027 break;
7028 }
7029 #ifndef NO_PKCS7_STREAM
7030 /* factor in that recent idx was in cert buffer. If in2 buffer was
7031 * used then don't advance idx. */
7032 if (length > 0 && pkcs7->stream->flagOne &&
7033 pkcs7->stream->length == 0) {
7034 idx = stateIdx + idx;
7035 if (idx > inSz) {
7036 /* index is more than input size */
7037 ret = BUFFER_E;
7038 break;
7039 }
7040 }
7041 if ((ret = wc_PKCS7_StreamEndCase(pkcs7, &stateIdx, &idx)) != 0) {
7042 break;
7043 }
7044
7045 pkcs7->stream->expected = MAX_OID_SZ + ASN_TAG_SZ + MAX_LENGTH_SZ +
7046 MAX_SET_SZ;
7047 /* if certificate set has indef-length, there maybe trailing zeros.
7048 * add expected size to include size of zeros. */
7049 if (pkcs7->stream->cntIdfCnt > 0) {
7050 pkcs7->stream->expected += (word32)pkcs7->stream->cntIdfCnt * 2;
7051 }
7052
7053 if (pkcs7->stream->expected > (pkcs7->stream->maxLen -
7054 pkcs7->stream->totalRd) + pkcs7->stream->length)
7055 pkcs7->stream->expected = (pkcs7->stream->maxLen -
7056 pkcs7->stream->totalRd) + pkcs7->stream->length;
7057
7058 wc_PKCS7_StreamGetVar(pkcs7, &pkiMsg2Sz, 0, 0);
7059 wc_PKCS7_StreamStoreVar(pkcs7, pkiMsg2Sz, 0, length);
7060 #endif
7061 wc_PKCS7_ChangeState(pkcs7, WC_PKCS7_VERIFY_STAGE6);
7062 FALL_THROUGH;
7063
7064 case WC_PKCS7_VERIFY_STAGE6:
7065 #ifndef NO_PKCS7_STREAM
7066
7067 if (in2 && in2Sz > 0) {
7068 src = in2;
7069 srcSz = in2Sz;
7070 pkiMsg2 = in2;
7071 }
7072 else {
7073 src = in;
7074 srcSz = inSz;
7075 pkiMsg2 = in;
7076 }
7077 if ((ret = wc_PKCS7_AddDataToStream(pkcs7, src, srcSz,
7078 pkcs7->stream->expected, &pkiMsg2, &idx)) != 0) {
7079 break;
7080 }
7081 wc_PKCS7_StreamGetVar(pkcs7, &pkiMsg2Sz, 0, &length);
7082
7083 /* check if using internal stream buffer and should adjust sz */
7084 pkiMsg2Sz = (pkcs7->stream->length > 0)? pkcs7->stream->length:
7085 srcSz;
7086
7087 /* restore content type */
7088 contentType = pkcs7->stream->nonce;
7089 contentTypeSz = pkcs7->stream->nonceSz;
7090
7091 maxIdx = idx + pkcs7->stream->expected;
7092 if (maxIdx > pkiMsg2Sz) {
7093 ret = BUFFER_E;
7094 break;
7095 }
7096 stateIdx = idx;
7097 #else
7098 /* if not streaming, maxIdx is just pkiMsg2Sz */
7099 maxIdx = pkiMsg2Sz;
7100 #endif
7101
7102 /* set contentType and size after init of PKCS7 structure */
7103 if (ret == 0 && wc_PKCS7_SetContentType(pkcs7, contentType,
7104 contentTypeSz) < 0)
7105 ret = ASN_PARSE_E;
7106 #ifndef NO_PKCS7_STREAM
7107 /* prior to find set of crls, remove trailing zeros of
7108 * set of certificates */
7109 if (ret == 0 && pkcs7->stream->cntIdfCnt > 0) {
7110 word32 i;
7111 word32 sz = (word32)pkcs7->stream->cntIdfCnt * ASN_INDEF_END_SZ;
7112 localIdx = idx;
7113 for (i = 0; i < sz; i++) {
7114 if (localIdx + i >= pkiMsg2Sz) {
7115 ret = ASN_PARSE_E;
7116 break;
7117 }
7118 if (pkiMsg2[localIdx + i] == 0)
7119 continue;
7120 else {
7121 ret = ASN_PARSE_E;
7122 break;
7123 }
7124 }
7125 if (ret == 0) {
7126 idx += (word32)pkcs7->stream->cntIdfCnt * ASN_INDEF_END_SZ;
7127 pkcs7->stream->cntIdfCnt = 0;
7128 }
7129 }
7130 #endif /* !NO_PKCS7_STREAM */
7131 /* Get the implicit[1] set of crls */
7132 if (ret == 0 && idx >= maxIdx)
7133 ret = BUFFER_E;
7134
7135 localIdx = idx;
7136 if (ret == 0 && GetASNTag(pkiMsg2, &localIdx, &tag, pkiMsg2Sz) == 0
7137 && tag == (ASN_CONSTRUCTED | ASN_CONTEXT_SPECIFIC | 1)) {
7138 idx++;
7139 if (GetLength(pkiMsg2, &idx, &length, pkiMsg2Sz) < 0)
7140 ret = ASN_PARSE_E;
7141
7142 /* Skip the set */
7143 idx += (word32)length;
7144 }
7145
7146 /* Get the set of signerInfos */
7147 if (ret == 0 && GetSet_ex(pkiMsg2, &idx, &length, maxIdx,
7148 NO_USER_CHECK) < 0)
7149 ret = ASN_PARSE_E;
7150
7151 /* Update degenerate flag based on if signerInfos SET is empty.
7152 * The earlier degenerate check at digestAlgorithms is an early
7153 * optimization, but depending on degenerate case may not be
7154 * detected until here. */
7155 if (ret == 0) {
7156 degenerate = (length == 0) ? 1 : 0;
7157 #ifndef NO_PKCS7_STREAM
7158 pkcs7->stream->degenerate = (degenerate != 0);
7159 #endif
7160 }
7161
7162 if (ret != 0)
7163 break;
7164 #ifndef NO_PKCS7_STREAM
7165 if (!pkcs7->stream->flagOne) {
7166 stateIdx = idx; /* didn't read any from internal buffer */
7167 }
7168 if ((ret = wc_PKCS7_StreamEndCase(pkcs7, &stateIdx, &idx)) != 0) {
7169 break;
7170 }
7171 wc_PKCS7_StreamStoreVar(pkcs7, pkiMsg2Sz, 0, length);
7172
7173 if (in2 && in2Sz > 0 && hashBuf && hashSz > 0) {
7174 if (length > 0) {
7175 pkcs7->stream->expected = (word32)length;
7176 }
7177 else {
7178 pkcs7->stream->expected = 0;
7179 }
7180 }
7181 else {
7182 /* last state expect the rest of the buffer */
7183 pkcs7->stream->expected = (pkcs7->stream->maxLen -
7184 pkcs7->stream->totalRd) + pkcs7->stream->length;
7185 }
7186 /* In case of indefinite length used in the bundle, terminating
7187 * zero's should exist at the end of the bundle.
7188 */
7189 if (pkcs7->stream->indefLen == 1) {
7190 pkcs7->stream->expected = (word32)length + 3 * ASN_INDEF_END_SZ;
7191 }
7192 else {
7193 pkcs7->stream->expected = (word32)length;
7194 }
7195
7196 wc_PKCS7_ChangeState(pkcs7, WC_PKCS7_VERIFY_STAGE7);
7197 #endif /* !NO_PKCS7_STREAM */
7198 FALL_THROUGH;
7199
7200 case WC_PKCS7_VERIFY_STAGE7:
7201 #ifndef NO_PKCS7_STREAM
7202 if (in2 && in2Sz > 0) {
7203 src = in2;
7204 srcSz = in2Sz;
7205 pkiMsg2 = in2;
7206 }
7207 else {
7208 src = in;
7209 srcSz = inSz;
7210 pkiMsg2 = in;
7211 }
7212 if ((ret = wc_PKCS7_AddDataToStream(pkcs7, src, srcSz,
7213 pkcs7->stream->expected, &pkiMsg2, &idx)) != 0) {
7214 break;
7215 }
7216
7217 wc_PKCS7_StreamGetVar(pkcs7, &pkiMsg2Sz, 0, &length);
7218 pkiMsg2Sz = (pkcs7->stream->length > 0)? pkcs7->stream->length:
7219 srcSz;
7220 degenerate = pkcs7->stream->degenerate;
7221
7222 /* restore content */
7223 content = pkcs7->stream->content;
7224 contentSz = (int)pkcs7->stream->contentSz;
7225 #endif
7226
7227 ret = wc_PKCS7_ParseSignerInfo(pkcs7, pkiMsg2, pkiMsg2Sz, &idx,
7228 degenerate, &signedAttrib, &signedAttribSz);
7229
7230 /* parse out the signature if present and verify it */
7231 if (ret == 0 && length > 0 && degenerate == 0) {
7232 WOLFSSL_MSG("Parsing signature and verifying");
7233 if (idx >= pkiMsg2Sz)
7234 ret = BUFFER_E;
7235
7236 /* Get the signature */
7237 localIdx = idx;
7238 if (ret == 0 && GetASNTag(pkiMsg2, &localIdx, &tag,
7239 pkiMsg2Sz) == 0 && tag == ASN_OCTET_STRING) {
7240 idx++;
7241
7242 if (GetLength(pkiMsg2, &idx, &length, pkiMsg2Sz) < 0)
7243 ret = ASN_PARSE_E;
7244
7245 /* save pointer and length */
7246 sig = &pkiMsg2[idx];
7247 sigSz = length;
7248
7249 idx += (word32)length;
7250 }
7251 else if (ret == 0) {
7252 ret = ASN_PARSE_E;
7253 }
7254
7255 pkcs7->content = content;
7256 pkcs7->contentSz = (word32)contentSz;
7257
7258 if (ret == 0) {
7259 #if !defined(NO_PKCS7_STREAM) && defined(ASN_BER_TO_DER)
7260 byte streamHash[WC_MAX_DIGEST_SIZE];
7261
7262 /* get final hash if having done hash updates while
7263 * streaming out the content */
7264 if (pkcs7->streamOutCb) {
7265 ret = wc_HashFinal(&pkcs7->stream->hashAlg,
7266 pkcs7->stream->hashType, streamHash);
7267 hashBuf = streamHash;
7268 length = wc_HashGetDigestSize(pkcs7->stream->hashType);
7269 if (length < 0) {
7270 WOLFSSL_MSG("Error getting digest size");
7271 ret = ASN_PARSE_E;
7272 }
7273 else {
7274 hashSz = (word32)length;
7275 }
7276 wc_HashFree(&pkcs7->stream->hashAlg,
7277 pkcs7->stream->hashType);
7278 if (ret != 0)
7279 break;
7280 }
7281 #endif /* !NO_PKCS7_STREAM && ASN_BER_TO_DER */
7282 ret = wc_PKCS7_SignedDataVerifySignature(pkcs7, sig,
7283 (word32)sigSz, signedAttrib, (word32)signedAttribSz,
7284 hashBuf, hashSz);
7285 }
7286 }
7287
7288 #ifndef NO_PKCS7_STREAM
7289 /* make sure that terminating zero's follow */
7290 if ((ret == WC_NO_ERR_TRACE(PKCS7_SIGNEEDS_CHECK) || ret >= 0) &&
7291 pkcs7->stream->indefLen == 1) {
7292 if (idx + (3 * ASN_INDEF_END_SZ) > pkiMsg2Sz) {
7293 ret = ASN_PARSE_E;
7294 }
7295 else {
7296 word32 i;
7297 for (i = 0; i < 3 * ASN_INDEF_END_SZ; i++) {
7298 if (pkiMsg2[idx + i] != 0) {
7299 ret = ASN_PARSE_E;
7300 break;
7301 }
7302 }
7303 }
7304 }
7305 #endif /* NO_PKCS7_STREAM */
7306
7307 if (ret < 0)
7308 break;
7309
7310
7311 ret = 0; /* success */
7312 #ifndef NO_PKCS7_STREAM
7313 wc_PKCS7_ResetStream(pkcs7);
7314 #endif
7315 wc_PKCS7_ChangeState(pkcs7, WC_PKCS7_START);
7316 break;
7317
7318 default:
7319 WOLFSSL_MSG("PKCS7 Unknown verify state");
7320 ret = BAD_FUNC_ARG;
7321 }
7322
7323 if (ret != 0 && ret != WC_NO_ERR_TRACE(WC_PKCS7_WANT_READ_E)) {
7324 #ifndef NO_PKCS7_STREAM
7325 wc_PKCS7_ResetStream(pkcs7);
7326 #endif
7327 wc_PKCS7_ChangeState(pkcs7, WC_PKCS7_START);
7328 }
7329 return ret;
7330}
7331
7332
7333/* Gets a copy of the SID parsed from signerInfo. This can be called after
7334 * wc_PKCS7_VerifySignedData has been called. SID can be SKID in version 3 case
7335 * or issuerAndSerialNumber.
7336 *
7337 * return 0 on success and LENGTH_ONLY_E if just setting "outSz" for buffer
7338 * length needed.
7339 */
7340int wc_PKCS7_GetSignerSID(wc_PKCS7* pkcs7, byte* out, word32* outSz)
7341{
7342 if (outSz == NULL || pkcs7 == NULL) {
7343 return BAD_FUNC_ARG;
7344 }
7345
7346 if (pkcs7->signerInfo == NULL) {
7347 WOLFSSL_MSG("Either the bundle had no signers or"
7348 "wc_PKCS7_VerifySignedData needs called yet");
7349 return PKCS7_NO_SIGNER_E;
7350 }
7351
7352 if (pkcs7->signerInfo->sidSz == 0) {
7353 WOLFSSL_MSG("Bundle had no signer SID set");
7354 return PKCS7_NO_SIGNER_E;
7355 }
7356
7357 if (out == NULL) {
7358 *outSz = pkcs7->signerInfo->sidSz;
7359 return WC_NO_ERR_TRACE(LENGTH_ONLY_E);
7360 }
7361
7362 if (*outSz < pkcs7->signerInfo->sidSz) {
7363 WOLFSSL_MSG("Buffer being passed in is not large enough for SKID");
7364 return BUFFER_E;
7365 }
7366 XMEMCPY(out, pkcs7->signerInfo->sid, pkcs7->signerInfo->sidSz);
7367 *outSz = pkcs7->signerInfo->sidSz;
7368 return 0;
7369}
7370
7371
7372/* SignedData verification function variant that allows pre-computed content
7373 * message digest and optional PKCS7/CMS bundle content header/footer to be
7374 * used for verification. Useful for large data signing.
7375 *
7376 * pkcs7 - pointer to initialized PKCS7 structure
7377 * hashBuf - message digest of content
7378 * hashSz - size of hashBuf, octets
7379 * pkiMsgHead - PKCS7/CMS header that goes on top of the raw data signed,
7380 * as output from wc_PKCS7_EncodeSignedData_ex (if also using
7381 * pkiMsgFoot). Otherwise, PKCS7/CMS bundle with
7382 * detached signature - will use hashBuf/hashSz to verify.
7383 * pkiMsgHeadSz - size of pkiMsgHead, octets
7384 * pkiMsgFoot - PKCS7/CMS footer that goes at the end of the raw data signed,
7385 * as output from wc_PKCS7_EncodeSignedData_ex. Can be NULL
7386 * if pkiMsgHead is a direct detached signature bundle to be used
7387 * with hashBuf/hashSz.
7388 * pkiMsgFootSz - size of pkiMsgFoot, octets. Should be 0 if pkiMsgFoot is NULL.
7389 *
7390 * Returns 0 on success, negative upon error.
7391 *
7392 */
7393int wc_PKCS7_VerifySignedData_ex(wc_PKCS7* pkcs7, const byte* hashBuf,
7394 word32 hashSz, byte* pkiMsgHead, word32 pkiMsgHeadSz, byte* pkiMsgFoot,
7395 word32 pkiMsgFootSz)
7396{
7397 return PKCS7_VerifySignedData(pkcs7, hashBuf, hashSz,
7398 pkiMsgHead, pkiMsgHeadSz, pkiMsgFoot, pkiMsgFootSz);
7399}
7400
7401int wc_PKCS7_VerifySignedData(wc_PKCS7* pkcs7, byte* pkiMsg, word32 pkiMsgSz)
7402{
7403 return PKCS7_VerifySignedData(pkcs7, NULL, 0, pkiMsg, pkiMsgSz, NULL, 0);
7404}
7405
7406
7407/* Generate random content encryption key, store into pkcs7->cek and
7408 * pkcs7->cekSz.
7409 *
7410 * pkcs7 - pointer to initialized PKCS7 structure
7411 * len - length of key to be generated
7412 *
7413 * Returns 0 on success, negative upon error */
7414static int PKCS7_GenerateContentEncryptionKey(wc_PKCS7* pkcs7, word32 len)
7415{
7416 int ret;
7417 WC_RNG rng;
7418 byte* tmpKey;
7419
7420 if (pkcs7 == NULL || len == 0)
7421 return BAD_FUNC_ARG;
7422
7423 /* if key already exists, don't need to re-generate */
7424 if (pkcs7->cek != NULL && pkcs7->cekSz != 0) {
7425
7426 /* if key exists, but is different size, return error */
7427 if (pkcs7->cekSz != len) {
7428 WOLFSSL_MSG("Random content-encryption key size is inconsistent "
7429 "between CMS recipients");
7430 return WC_KEY_SIZE_E;
7431 }
7432
7433 return 0;
7434 }
7435
7436 /* allocate space for cek */
7437 tmpKey = (byte*)XMALLOC(len, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
7438 if (tmpKey == NULL)
7439 return MEMORY_E;
7440
7441 XMEMSET(tmpKey, 0, len);
7442
7443 ret = wc_InitRng_ex(&rng, pkcs7->heap, pkcs7->devId);
7444 if (ret != 0) {
7445 XFREE(tmpKey, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
7446 return ret;
7447 }
7448
7449 ret = wc_RNG_GenerateBlock(&rng, tmpKey, len);
7450 if (ret != 0) {
7451 wc_FreeRng(&rng);
7452 XFREE(tmpKey, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
7453 return ret;
7454 }
7455
7456 /* store into PKCS7, memory freed during final cleanup */
7457 pkcs7->cek = tmpKey;
7458 pkcs7->cekSz = len;
7459
7460 wc_FreeRng(&rng);
7461
7462 return 0;
7463}
7464
7465
7466/* wrap CEK (content encryption key) with KEK, returns output size (> 0) on
7467 * success, < 0 on error */
7468static int wc_PKCS7_KeyWrap(const wc_PKCS7 * pkcs7, const byte * cek,
7469 word32 cekSz, const byte * kek, word32 kekSz, byte * out, word32 outSz,
7470 int keyWrapAlgo, int direction)
7471{
7472 int ret = 0;
7473
7474 if (pkcs7 == NULL || cek == NULL || kek == NULL || out == NULL)
7475 return BAD_FUNC_ARG;
7476
7477 switch (keyWrapAlgo) {
7478#ifndef NO_AES
7479 #ifdef WOLFSSL_AES_128
7480 case AES128_WRAP:
7481 #endif
7482 #ifdef WOLFSSL_AES_192
7483 case AES192_WRAP:
7484 #endif
7485 #ifdef WOLFSSL_AES_256
7486 case AES256_WRAP:
7487 #endif
7488
7489 if (direction == AES_ENCRYPTION) {
7490 if (pkcs7->aesKeyWrapUnwrapCb != NULL) {
7491 ret = pkcs7->aesKeyWrapUnwrapCb(kek, kekSz, cek, cekSz, 1,
7492 out, outSz);
7493 }
7494 else {
7495 #ifdef HAVE_AES_KEYWRAP
7496 ret = wc_AesKeyWrap(kek, kekSz, cek, cekSz,
7497 out, outSz, NULL);
7498 #else
7499 ret = NOT_COMPILED_IN;
7500 #endif
7501 }
7502
7503 } else if (direction == AES_DECRYPTION) {
7504 if (pkcs7->aesKeyWrapUnwrapCb != NULL) {
7505 ret = pkcs7->aesKeyWrapUnwrapCb(kek, kekSz, cek, cekSz, 0,
7506 out, outSz);
7507 }
7508 else {
7509 #ifdef HAVE_AES_KEYWRAP
7510 ret = wc_AesKeyUnWrap(kek, kekSz, cek, cekSz,
7511 out, outSz, NULL);
7512 #else
7513 ret = NOT_COMPILED_IN;
7514 #endif
7515 }
7516 } else {
7517 WOLFSSL_MSG("Bad key un/wrap direction");
7518 return BAD_FUNC_ARG;
7519 }
7520
7521 if (ret <= 0)
7522 return ret;
7523 break;
7524#endif /* NO_AES */
7525
7526 default:
7527 WOLFSSL_MSG("Unsupported key wrap algorithm");
7528 return BAD_KEYWRAP_ALG_E;
7529 };
7530
7531 (void)cekSz;
7532 (void)kekSz;
7533 (void)outSz;
7534 (void)direction;
7535 return ret;
7536}
7537
7538
7539#ifdef HAVE_ECC
7540
7541/* KARI == KeyAgreeRecipientInfo (key agreement) */
7542typedef struct WC_PKCS7_KARI {
7543 DecodedCert* decoded; /* decoded recip cert */
7544 void* heap; /* user heap, points to PKCS7->heap */
7545 int devId; /* device ID for HW based private key */
7546 ecc_key* recipKey; /* recip key (pub | priv) */
7547 ecc_key* senderKey; /* sender key (pub | priv) */
7548 byte* senderKeyExport; /* sender ephemeral key DER */
7549 byte* kek; /* key encryption key */
7550 byte* ukm; /* OPTIONAL user keying material */
7551 byte* sharedInfo; /* ECC-CMS-SharedInfo ASN.1 encoded blob */
7552 word32 senderKeyExportSz; /* size of sender ephemeral key DER */
7553 word32 kekSz; /* size of key encryption key */
7554 word32 ukmSz; /* size of user keying material */
7555 word32 sharedInfoSz; /* size of ECC-CMS-SharedInfo encoded */
7556 byte ukmOwner; /* do we own ukm buffer? 1:yes, 0:no */
7557 byte direction; /* WC_PKCS7_ENCODE | WC_PKCS7_DECODE */
7558 WC_BITFIELD decodedInit:1; /* indicates decoded was initialized */
7559 WC_BITFIELD recipKeyInit:1; /* indicates recipKey was initialized */
7560 WC_BITFIELD senderKeyInit:1; /* indicates senderKey was initialized */
7561} WC_PKCS7_KARI;
7562
7563
7564/* allocate and create new WC_PKCS7_KARI struct,
7565 * returns struct pointer on success, NULL on failure */
7566static WC_PKCS7_KARI* wc_PKCS7_KariNew(wc_PKCS7* pkcs7, byte direction)
7567{
7568 WC_PKCS7_KARI* kari = NULL;
7569
7570 if (pkcs7 == NULL)
7571 return NULL;
7572
7573 kari = (WC_PKCS7_KARI*)XMALLOC(sizeof(WC_PKCS7_KARI), pkcs7->heap,
7574 DYNAMIC_TYPE_PKCS7);
7575 if (kari == NULL) {
7576 WOLFSSL_MSG("Failed to allocate WC_PKCS7_KARI");
7577 return NULL;
7578 }
7579
7580 kari->decoded = (DecodedCert*)XMALLOC(sizeof(DecodedCert), pkcs7->heap,
7581 DYNAMIC_TYPE_PKCS7);
7582 if (kari->decoded == NULL) {
7583 WOLFSSL_MSG("Failed to allocate DecodedCert");
7584 XFREE(kari, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
7585 return NULL;
7586 }
7587 XMEMSET(kari->decoded, 0, sizeof(DecodedCert));
7588
7589 kari->recipKey = (ecc_key*)XMALLOC(sizeof(ecc_key), pkcs7->heap,
7590 DYNAMIC_TYPE_PKCS7);
7591 if (kari->recipKey == NULL) {
7592 WOLFSSL_MSG("Failed to allocate recipient ecc_key");
7593 XFREE(kari->decoded, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
7594 XFREE(kari, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
7595 return NULL;
7596 }
7597
7598 kari->senderKey = (ecc_key*)XMALLOC(sizeof(ecc_key), pkcs7->heap,
7599 DYNAMIC_TYPE_PKCS7);
7600 if (kari->senderKey == NULL) {
7601 WOLFSSL_MSG("Failed to allocate sender ecc_key");
7602 XFREE(kari->recipKey, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
7603 XFREE(kari->decoded, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
7604 XFREE(kari, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
7605 return NULL;
7606 }
7607
7608 kari->senderKeyExport = NULL;
7609 kari->senderKeyExportSz = 0;
7610 kari->kek = NULL;
7611 kari->kekSz = 0;
7612 kari->ukm = NULL;
7613 kari->ukmSz = 0;
7614 kari->ukmOwner = 0;
7615 kari->sharedInfo = NULL;
7616 kari->sharedInfoSz = 0;
7617 kari->direction = direction;
7618 kari->decodedInit = 0;
7619 kari->recipKeyInit = 0;
7620 kari->senderKeyInit = 0;
7621
7622 kari->heap = pkcs7->heap;
7623 kari->devId = pkcs7->devId;
7624
7625 return kari;
7626}
7627
7628
7629/* free WC_PKCS7_KARI struct, return 0 on success */
7630static int wc_PKCS7_KariFree(WC_PKCS7_KARI* kari)
7631{
7632 void* heap;
7633
7634 if (kari) {
7635 heap = kari->heap;
7636
7637 if (kari->decoded) {
7638 if (kari->decodedInit)
7639 FreeDecodedCert(kari->decoded);
7640 XFREE(kari->decoded, heap, DYNAMIC_TYPE_PKCS7);
7641 }
7642 if (kari->senderKey) {
7643 if (kari->senderKeyInit)
7644 wc_ecc_free(kari->senderKey);
7645 XFREE(kari->senderKey, heap, DYNAMIC_TYPE_PKCS7);
7646 }
7647 if (kari->recipKey) {
7648 if (kari->recipKeyInit)
7649 wc_ecc_free(kari->recipKey);
7650 XFREE(kari->recipKey, heap, DYNAMIC_TYPE_PKCS7);
7651 }
7652 if (kari->senderKeyExport) {
7653 ForceZero(kari->senderKeyExport, kari->senderKeyExportSz);
7654 XFREE(kari->senderKeyExport, heap, DYNAMIC_TYPE_PKCS7);
7655 kari->senderKeyExportSz = 0;
7656 }
7657 if (kari->kek) {
7658 ForceZero(kari->kek, kari->kekSz);
7659 XFREE(kari->kek, heap, DYNAMIC_TYPE_PKCS7);
7660 kari->kekSz = 0;
7661 }
7662 if (kari->ukm) {
7663 if (kari->ukmOwner == 1) {
7664 XFREE(kari->ukm, heap, DYNAMIC_TYPE_PKCS7);
7665 }
7666 kari->ukmSz = 0;
7667 }
7668 if (kari->sharedInfo) {
7669 ForceZero(kari->sharedInfo, kari->sharedInfoSz);
7670 XFREE(kari->sharedInfo, heap, DYNAMIC_TYPE_PKCS7);
7671 kari->sharedInfoSz = 0;
7672 }
7673 XFREE(kari, heap, DYNAMIC_TYPE_PKCS7);
7674 }
7675
7676 (void)heap;
7677
7678 return 0;
7679}
7680
7681
7682/* parse recipient cert/key, return 0 on success, negative on error
7683 * key/keySz only needed during decoding (WC_PKCS7_DECODE) */
7684static int wc_PKCS7_KariParseRecipCert(WC_PKCS7_KARI* kari, const byte* cert,
7685 word32 certSz, const byte* key,
7686 word32 keySz)
7687{
7688 int ret;
7689 word32 idx;
7690
7691 if (kari == NULL || kari->decoded == NULL) {
7692 return BAD_FUNC_ARG;
7693 }
7694
7695 /* decode certificate */
7696 if (cert != NULL) {
7697 InitDecodedCert(kari->decoded, cert, certSz, kari->heap);
7698 kari->decodedInit = 1;
7699 ret = ParseCert(kari->decoded, CA_TYPE, NO_VERIFY, 0);
7700 if (ret < 0)
7701 return ret;
7702
7703 /* only supports ECDSA for now */
7704 if (kari->decoded->keyOID != ECDSAk) {
7705 WOLFSSL_MSG("CMS KARI only supports ECDSA key types");
7706 return BAD_FUNC_ARG;
7707 }
7708
7709 /* make sure subject key id was read from cert */
7710 if (kari->decoded->extSubjKeyIdSet == 0) {
7711 WOLFSSL_MSG("Failed to read subject key ID from recipient cert");
7712 return BAD_FUNC_ARG;
7713 }
7714 }
7715 ret = wc_ecc_init_ex(kari->recipKey, kari->heap, kari->devId);
7716 if (ret != 0)
7717 return ret;
7718
7719 kari->recipKeyInit = 1;
7720
7721 /* get recip public key */
7722 if (kari->direction == WC_PKCS7_ENCODE) {
7723 if (cert == NULL) {
7724 WOLFSSL_MSG("Error recipient cert can not be null with encode");
7725 return BAD_FUNC_ARG;
7726 }
7727
7728 idx = 0;
7729 ret = wc_EccPublicKeyDecode(kari->decoded->publicKey, &idx,
7730 kari->recipKey, kari->decoded->pubKeySize);
7731 if (ret != 0)
7732 return ret;
7733 }
7734 /* get recip private key */
7735 else if (kari->direction == WC_PKCS7_DECODE) {
7736 if (key != NULL && keySz > 0) {
7737 idx = 0;
7738 ret = wc_EccPrivateKeyDecode(key, &idx, kari->recipKey, keySz);
7739 }
7740 else if (kari->devId == INVALID_DEVID) {
7741 ret = BAD_FUNC_ARG;
7742 }
7743 if (ret != 0)
7744 return ret;
7745
7746 } else {
7747 /* bad direction */
7748 return BAD_FUNC_ARG;
7749 }
7750
7751 (void)idx;
7752
7753 return 0;
7754}
7755
7756
7757/* create ephemeral ECC key, places ecc_key in kari->senderKey,
7758 * DER encoded in kari->senderKeyExport. return 0 on success,
7759 * negative on error */
7760static int wc_PKCS7_KariGenerateEphemeralKey(WC_PKCS7_KARI* kari)
7761{
7762 int ret;
7763 WC_RNG rng;
7764
7765 if (kari == NULL || kari->decoded == NULL ||
7766 kari->recipKey == NULL || kari->recipKey->dp == NULL)
7767 return BAD_FUNC_ARG;
7768
7769 kari->senderKeyExport = (byte*)XMALLOC(kari->decoded->pubKeySize,
7770 kari->heap, DYNAMIC_TYPE_PKCS7);
7771 if (kari->senderKeyExport == NULL)
7772 return MEMORY_E;
7773
7774 kari->senderKeyExportSz = kari->decoded->pubKeySize;
7775
7776 ret = wc_ecc_init_ex(kari->senderKey, kari->heap, kari->devId);
7777 if (ret != 0) {
7778 XFREE(kari->senderKeyExport, kari->heap, DYNAMIC_TYPE_PKCS7);
7779 kari->senderKeyExportSz = 0;
7780 kari->senderKeyExport = NULL;
7781 return ret;
7782 }
7783
7784 kari->senderKeyInit = 1;
7785
7786 ret = wc_InitRng_ex(&rng, kari->heap, kari->devId);
7787 if (ret != 0) {
7788 XFREE(kari->senderKeyExport, kari->heap, DYNAMIC_TYPE_PKCS7);
7789 kari->senderKeyExportSz = 0;
7790 kari->senderKeyExport = NULL;
7791 return ret;
7792 }
7793
7794 ret = wc_ecc_make_key_ex(&rng, kari->recipKey->dp->size,
7795 kari->senderKey, kari->recipKey->dp->id);
7796 if (ret != 0) {
7797 XFREE(kari->senderKeyExport, kari->heap, DYNAMIC_TYPE_PKCS7);
7798 kari->senderKeyExportSz = 0;
7799 kari->senderKeyExport = NULL;
7800 wc_FreeRng(&rng);
7801 return ret;
7802 }
7803
7804 wc_FreeRng(&rng);
7805
7806 /* dump generated key to X.963 DER for output in CMS bundle */
7807 PRIVATE_KEY_UNLOCK();
7808 ret = wc_ecc_export_x963(kari->senderKey, kari->senderKeyExport,
7809 &kari->senderKeyExportSz);
7810 PRIVATE_KEY_LOCK();
7811 if (ret != 0) {
7812 XFREE(kari->senderKeyExport, kari->heap, DYNAMIC_TYPE_PKCS7);
7813 kari->senderKeyExportSz = 0;
7814 kari->senderKeyExport = NULL;
7815 return ret;
7816 }
7817
7818 return 0;
7819}
7820
7821
7822/* create ASN.1 encoded ECC-CMS-SharedInfo using specified key wrap algorithm,
7823 * place in kari->sharedInfo. returns 0 on success, negative on error */
7824static int wc_PKCS7_KariGenerateSharedInfo(WC_PKCS7_KARI* kari, int keyWrapOID)
7825{
7826 int idx = 0;
7827 int sharedInfoSeqSz = 0;
7828 int keyInfoSz = 0;
7829 int suppPubInfoSeqSz = 0;
7830 int entityUInfoOctetSz = 0;
7831 int entityUInfoExplicitSz = 0;
7832 int kekOctetSz = 0;
7833 int sharedInfoSz = 0;
7834
7835 word32 kekBitSz = 0;
7836
7837 byte sharedInfoSeq[MAX_SEQ_SZ];
7838 byte keyInfo[MAX_ALGO_SZ];
7839 byte suppPubInfoSeq[MAX_SEQ_SZ];
7840 byte entityUInfoOctet[MAX_OCTET_STR_SZ];
7841 byte entityUInfoExplicitSeq[MAX_SEQ_SZ];
7842 byte kekOctet[MAX_OCTET_STR_SZ];
7843
7844 if (kari == NULL)
7845 return BAD_FUNC_ARG;
7846
7847 if ((kari->ukmSz > 0) && (kari->ukm == NULL))
7848 return BAD_FUNC_ARG;
7849
7850 /* kekOctet */
7851 kekOctetSz = (int)SetOctetString(sizeof(word32), kekOctet);
7852 sharedInfoSz += (kekOctetSz + (int)sizeof(word32));
7853
7854 /* suppPubInfo */
7855 suppPubInfoSeqSz = (int)SetImplicit(ASN_SEQUENCE, 2,
7856 (word32)kekOctetSz + (word32)sizeof(word32),
7857 suppPubInfoSeq, 0);
7858 sharedInfoSz += suppPubInfoSeqSz;
7859
7860 /* optional ukm/entityInfo */
7861 if (kari->ukmSz > 0) {
7862 entityUInfoOctetSz = (int)SetOctetString(kari->ukmSz, entityUInfoOctet);
7863 sharedInfoSz += (entityUInfoOctetSz + (int)kari->ukmSz);
7864
7865 entityUInfoExplicitSz = (int)SetExplicit(0,
7866 (word32)entityUInfoOctetSz + kari->ukmSz,
7867 entityUInfoExplicitSeq, 0);
7868 sharedInfoSz += entityUInfoExplicitSz;
7869 }
7870
7871 /* keyInfo */
7872 keyInfoSz = (int)SetAlgoID(keyWrapOID, keyInfo, oidKeyWrapType, 0);
7873 sharedInfoSz += keyInfoSz;
7874
7875 /* sharedInfo */
7876 sharedInfoSeqSz = (int)SetSequence((word32)sharedInfoSz, sharedInfoSeq);
7877 sharedInfoSz += sharedInfoSeqSz;
7878
7879 kari->sharedInfo = (byte*)XMALLOC((word32)sharedInfoSz, kari->heap,
7880 DYNAMIC_TYPE_PKCS7);
7881 if (kari->sharedInfo == NULL)
7882 return MEMORY_E;
7883
7884 kari->sharedInfoSz = (word32)sharedInfoSz;
7885
7886 XMEMCPY(kari->sharedInfo + idx, sharedInfoSeq, (word32)sharedInfoSeqSz);
7887 idx += sharedInfoSeqSz;
7888 XMEMCPY(kari->sharedInfo + idx, keyInfo, (word32)keyInfoSz);
7889 idx += keyInfoSz;
7890 if (kari->ukmSz > 0) {
7891 XMEMCPY(kari->sharedInfo + idx, entityUInfoExplicitSeq,
7892 (word32)entityUInfoExplicitSz);
7893 idx += entityUInfoExplicitSz;
7894 XMEMCPY(kari->sharedInfo + idx, entityUInfoOctet,
7895 (word32)entityUInfoOctetSz);
7896 idx += entityUInfoOctetSz;
7897 XMEMCPY(kari->sharedInfo + idx, kari->ukm, kari->ukmSz);
7898 idx += (int)kari->ukmSz;
7899 }
7900 XMEMCPY(kari->sharedInfo + idx, suppPubInfoSeq, (word32)suppPubInfoSeqSz);
7901 idx += suppPubInfoSeqSz;
7902 XMEMCPY(kari->sharedInfo + idx, kekOctet, (word32)kekOctetSz);
7903 idx += kekOctetSz;
7904
7905 kekBitSz = (kari->kekSz) * 8; /* convert to bits */
7906#ifdef LITTLE_ENDIAN_ORDER
7907 kekBitSz = ByteReverseWord32(kekBitSz); /* network byte order */
7908#endif
7909 XMEMCPY(kari->sharedInfo + idx, &kekBitSz, sizeof(kekBitSz));
7910
7911 return 0;
7912}
7913
7914
7915/* create key encryption key (KEK) using key wrap algorithm and key encryption
7916 * algorithm, place in kari->kek. return 0 on success, <0 on error. */
7917static int wc_PKCS7_KariGenerateKEK(WC_PKCS7_KARI* kari, WC_RNG* rng,
7918 int keyWrapOID, int keyEncOID)
7919{
7920 int ret;
7921 int kSz;
7922 enum wc_HashType kdfType;
7923 byte* secret;
7924 word32 secretSz;
7925
7926 if (kari == NULL || kari->recipKey == NULL ||
7927 kari->senderKey == NULL || kari->senderKey->dp == NULL)
7928 return BAD_FUNC_ARG;
7929
7930 /* get KEK size, allocate buff */
7931 kSz = wc_PKCS7_GetOIDKeySize(keyWrapOID);
7932 if (kSz < 0)
7933 return kSz;
7934
7935 kari->kek = (byte*)XMALLOC((word32)kSz, kari->heap, DYNAMIC_TYPE_PKCS7);
7936 if (kari->kek == NULL)
7937 return MEMORY_E;
7938
7939 kari->kekSz = (word32)kSz;
7940
7941 /* generate ECC-CMS-SharedInfo */
7942 ret = wc_PKCS7_KariGenerateSharedInfo(kari, keyWrapOID);
7943 if (ret != 0)
7944 return ret;
7945
7946 /* generate shared secret */
7947 secretSz = (word32)kari->senderKey->dp->size;
7948 secret = (byte*)XMALLOC(secretSz, kari->heap, DYNAMIC_TYPE_PKCS7);
7949 if (secret == NULL)
7950 return MEMORY_E;
7951#ifdef WOLFSSL_CHECK_MEM_ZERO
7952 wc_MemZero_Add("wc_PKCS7_KariGenerateKEK secret", secret, secretSz);
7953#endif
7954
7955#if defined(ECC_TIMING_RESISTANT) && (!defined(HAVE_FIPS) || \
7956 (!defined(HAVE_FIPS_VERSION) || (HAVE_FIPS_VERSION != 2))) && \
7957 !defined(HAVE_SELFTEST)
7958 ret = wc_ecc_set_rng(kari->senderKey, rng);
7959 if (ret != 0) {
7960 XFREE(secret, kari->heap, DYNAMIC_TYPE_PKCS7);
7961 return ret;
7962 }
7963 ret = wc_ecc_set_rng(kari->recipKey, rng);
7964 if (ret != 0) {
7965 XFREE(secret, kari->heap, DYNAMIC_TYPE_PKCS7);
7966 return ret;
7967 }
7968#else
7969 (void)rng;
7970#endif
7971
7972 if (kari->direction == WC_PKCS7_ENCODE) {
7973 PRIVATE_KEY_UNLOCK();
7974 ret = wc_ecc_shared_secret(kari->senderKey, kari->recipKey,
7975 secret, &secretSz);
7976 PRIVATE_KEY_LOCK();
7977 } else if (kari->direction == WC_PKCS7_DECODE) {
7978 PRIVATE_KEY_UNLOCK();
7979 ret = wc_ecc_shared_secret(kari->recipKey, kari->senderKey,
7980 secret, &secretSz);
7981 PRIVATE_KEY_LOCK();
7982 } else {
7983 /* bad direction */
7984 XFREE(secret, kari->heap, DYNAMIC_TYPE_PKCS7);
7985 return BAD_FUNC_ARG;
7986 }
7987
7988 if (ret != 0) {
7989 ForceZero(secret, secretSz);
7990 XFREE(secret, kari->heap, DYNAMIC_TYPE_PKCS7);
7991 return ret;
7992 }
7993
7994 /* run through KDF */
7995 switch (keyEncOID) {
7996
7997 #ifndef NO_SHA
7998 case dhSinglePass_stdDH_sha1kdf_scheme:
7999 kdfType = WC_HASH_TYPE_SHA;
8000 break;
8001 #endif
8002 #ifdef WOLFSSL_SHA224
8003 case dhSinglePass_stdDH_sha224kdf_scheme:
8004 kdfType = WC_HASH_TYPE_SHA224;
8005 break;
8006 #endif
8007 #ifndef NO_SHA256
8008 case dhSinglePass_stdDH_sha256kdf_scheme:
8009 kdfType = WC_HASH_TYPE_SHA256;
8010 break;
8011 #endif
8012 #ifdef WOLFSSL_SHA384
8013 case dhSinglePass_stdDH_sha384kdf_scheme:
8014 kdfType = WC_HASH_TYPE_SHA384;
8015 break;
8016 #endif
8017 #ifdef WOLFSSL_SHA512
8018 case dhSinglePass_stdDH_sha512kdf_scheme:
8019 kdfType = WC_HASH_TYPE_SHA512;
8020 break;
8021 #endif
8022 default:
8023 WOLFSSL_MSG("Unsupported key agreement algorithm");
8024 ForceZero(secret, secretSz);
8025 XFREE(secret, kari->heap, DYNAMIC_TYPE_PKCS7);
8026 return BAD_FUNC_ARG;
8027 };
8028
8029#ifdef HAVE_X963_KDF
8030 ret = wc_X963_KDF(kdfType, secret, secretSz, kari->sharedInfo,
8031 kari->sharedInfoSz, kari->kek, kari->kekSz);
8032#else
8033 (void)kdfType;
8034 ret = NOT_COMPILED_IN;
8035#endif
8036
8037 ForceZero(secret, secretSz);
8038 XFREE(secret, kari->heap, DYNAMIC_TYPE_PKCS7);
8039 return ret;
8040}
8041
8042
8043/* Encode and add CMS EnvelopedData KARI (KeyAgreeRecipientInfo) RecipientInfo
8044 * to CMS/PKCS#7 EnvelopedData structure.
8045 *
8046 * Returns 0 on success, negative upon error */
8047int wc_PKCS7_AddRecipient_KARI(wc_PKCS7* pkcs7, const byte* cert, word32 certSz,
8048 int keyWrapOID, int keyAgreeOID, byte* ukm,
8049 word32 ukmSz, int options)
8050{
8051 Pkcs7EncodedRecip* recip;
8052 Pkcs7EncodedRecip* lastRecip = NULL;
8053 WC_PKCS7_KARI* kari = NULL;
8054
8055 word32 idx = 0;
8056 word32 encryptedKeySz = MAX_ENCRYPTED_KEY_SZ;
8057
8058 int ret = 0;
8059 int keySz, direction = 0;
8060 int blockKeySz = 0;
8061 int keyIdSize;
8062
8063 /* ASN.1 layout */
8064 int totalSz = 0;
8065 int kariSeqSz = 0;
8066 byte kariSeq[MAX_SEQ_SZ]; /* IMPLICIT [1] */
8067 int verSz = 0;
8068 byte ver[MAX_VERSION_SZ];
8069
8070 int origIdOrKeySeqSz = 0;
8071 byte origIdOrKeySeq[MAX_SEQ_SZ]; /* IMPLICIT [0] */
8072 int origPubKeySeqSz = 0;
8073 byte origPubKeySeq[MAX_SEQ_SZ]; /* IMPLICIT [1] */
8074 int origAlgIdSz = 0;
8075 byte origAlgId[MAX_ALGO_SZ];
8076 int origPubKeyStrSz = 0;
8077 byte origPubKeyStr[MAX_OCTET_STR_SZ];
8078
8079 /* optional user keying material */
8080 int ukmOctetSz = 0;
8081 byte ukmOctetStr[MAX_OCTET_STR_SZ];
8082 int ukmExplicitSz = 0;
8083 byte ukmExplicitSeq[MAX_SEQ_SZ];
8084
8085 int keyEncryptAlgoIdSz = 0;
8086 byte keyEncryptAlgoId[MAX_ALGO_SZ];
8087 int keyWrapAlgSz = 0;
8088 byte keyWrapAlg[MAX_ALGO_SZ];
8089
8090 int recipEncKeysSeqSz = 0;
8091 byte recipEncKeysSeq[MAX_SEQ_SZ];
8092 int recipEncKeySeqSz = 0;
8093 byte recipEncKeySeq[MAX_SEQ_SZ];
8094 int recipKeyIdSeqSz = 0;
8095 byte recipKeyIdSeq[MAX_SEQ_SZ]; /* IMPLICIT [0] */
8096 int subjKeyIdOctetSz = 0;
8097 byte subjKeyIdOctet[MAX_OCTET_STR_SZ];
8098 int encryptedKeyOctetSz = 0;
8099 byte encryptedKeyOctet[MAX_OCTET_STR_SZ];
8100
8101#ifdef WOLFSSL_SMALL_STACK
8102 byte* encryptedKey;
8103
8104 encryptedKey = (byte*)XMALLOC(MAX_ENCRYPTED_KEY_SZ, pkcs7->heap,
8105 DYNAMIC_TYPE_TMP_BUFFER);
8106 if (encryptedKey == NULL) {
8107 return MEMORY_E;
8108 }
8109#else
8110 byte encryptedKey[MAX_ENCRYPTED_KEY_SZ];
8111#endif
8112
8113#if defined(WOLFSSL_SM2) && defined(WOLFSSL_SM3)
8114 keyIdSize = wc_HashGetDigestSize(wc_HashTypeConvert(HashIdAlg(
8115 pkcs7->publicKeyOID)));
8116#else
8117 keyIdSize = KEYID_SIZE;
8118#endif
8119
8120 /* allocate and init memory for recipient */
8121 recip = (Pkcs7EncodedRecip*)XMALLOC(sizeof(Pkcs7EncodedRecip), pkcs7->heap,
8122 DYNAMIC_TYPE_PKCS7);
8123 if (recip == NULL) {
8124 WC_FREE_VAR_EX(encryptedKey, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
8125 return MEMORY_E;
8126 }
8127 XMEMSET(recip, 0, sizeof(Pkcs7EncodedRecip));
8128
8129 /* get key size for content-encryption key based on algorithm */
8130 blockKeySz = wc_PKCS7_GetOIDKeySize(pkcs7->encryptOID);
8131 if (blockKeySz < 0) {
8132 WC_FREE_VAR_EX(encryptedKey, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
8133 XFREE(recip, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
8134 return blockKeySz;
8135 }
8136
8137 /* generate random content encryption key, if needed */
8138 ret = PKCS7_GenerateContentEncryptionKey(pkcs7, (word32)blockKeySz);
8139 if (ret < 0) {
8140 WC_FREE_VAR_EX(encryptedKey, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
8141 XFREE(recip, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
8142 return ret;
8143 }
8144
8145 /* set direction based on keyWrapAlgo */
8146 switch (keyWrapOID) {
8147#ifndef NO_AES
8148 #ifdef WOLFSSL_AES_128
8149 case AES128_WRAP:
8150 #endif
8151 #ifdef WOLFSSL_AES_192
8152 case AES192_WRAP:
8153 #endif
8154 #ifdef WOLFSSL_AES_256
8155 case AES256_WRAP:
8156 #endif
8157 direction = AES_ENCRYPTION;
8158 break;
8159#endif
8160 default:
8161 WOLFSSL_MSG("Unsupported key wrap algorithm");
8162 WC_FREE_VAR_EX(encryptedKey, pkcs7->heap,
8163 DYNAMIC_TYPE_TMP_BUFFER);
8164 XFREE(recip, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
8165 return BAD_KEYWRAP_ALG_E;
8166 }
8167
8168 kari = wc_PKCS7_KariNew(pkcs7, WC_PKCS7_ENCODE);
8169 if (kari == NULL) {
8170 WC_FREE_VAR_EX(encryptedKey, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
8171 XFREE(recip, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
8172 return MEMORY_E;
8173 }
8174
8175 /* set user keying material if available */
8176 if (ukmSz > 0 && ukm != NULL) {
8177 kari->ukm = ukm;
8178 kari->ukmSz = ukmSz;
8179 kari->ukmOwner = 0;
8180 }
8181
8182 /* parse recipient cert, get public key */
8183 ret = wc_PKCS7_KariParseRecipCert(kari, cert, certSz, NULL, 0);
8184 if (ret != 0) {
8185 wc_PKCS7_KariFree(kari);
8186 WC_FREE_VAR_EX(encryptedKey, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
8187 XFREE(recip, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
8188 return ret;
8189 }
8190
8191 /* generate sender ephemeral ECC key */
8192 ret = wc_PKCS7_KariGenerateEphemeralKey(kari);
8193 if (ret != 0) {
8194 wc_PKCS7_KariFree(kari);
8195 WC_FREE_VAR_EX(encryptedKey, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
8196 XFREE(recip, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
8197 return ret;
8198 }
8199
8200 /* generate KEK (key encryption key) */
8201 ret = wc_PKCS7_KariGenerateKEK(kari, pkcs7->rng, keyWrapOID, keyAgreeOID);
8202 if (ret != 0) {
8203 wc_PKCS7_KariFree(kari);
8204 WC_FREE_VAR_EX(encryptedKey, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
8205 XFREE(recip, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
8206 return ret;
8207 }
8208
8209 /* encrypt CEK with KEK */
8210 keySz = wc_PKCS7_KeyWrap(pkcs7, pkcs7->cek, pkcs7->cekSz, kari->kek,
8211 kari->kekSz, encryptedKey, encryptedKeySz,
8212 keyWrapOID, direction);
8213 if (keySz <= 0) {
8214 wc_PKCS7_KariFree(kari);
8215 WC_FREE_VAR_EX(encryptedKey, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
8216 XFREE(recip, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
8217 return keySz;
8218 }
8219 encryptedKeySz = (word32)keySz;
8220
8221 /* Start of RecipientEncryptedKeys */
8222
8223 /* EncryptedKey */
8224 encryptedKeyOctetSz = (int)SetOctetString(encryptedKeySz,
8225 encryptedKeyOctet);
8226 totalSz += (encryptedKeyOctetSz + (int)encryptedKeySz);
8227
8228 /* SubjectKeyIdentifier */
8229 subjKeyIdOctetSz = (int)SetOctetString((word32)keyIdSize, subjKeyIdOctet);
8230 totalSz += (subjKeyIdOctetSz + keyIdSize);
8231
8232 /* RecipientKeyIdentifier IMPLICIT [0] */
8233 recipKeyIdSeqSz = (int)SetImplicit(ASN_SEQUENCE, 0,
8234 (word32)(subjKeyIdOctetSz + keyIdSize),
8235 recipKeyIdSeq, 0);
8236 totalSz += recipKeyIdSeqSz;
8237
8238 /* RecipientEncryptedKey */
8239 recipEncKeySeqSz = (int)SetSequence((word32)totalSz, recipEncKeySeq);
8240 totalSz += recipEncKeySeqSz;
8241
8242 /* RecipientEncryptedKeys */
8243 recipEncKeysSeqSz = (int)SetSequence((word32)totalSz, recipEncKeysSeq);
8244 totalSz += recipEncKeysSeqSz;
8245
8246 /* Start of optional UserKeyingMaterial */
8247
8248 if (kari->ukmSz > 0) {
8249 ukmOctetSz = (int)SetOctetString(kari->ukmSz, ukmOctetStr);
8250 totalSz += (ukmOctetSz + (int)kari->ukmSz);
8251
8252 ukmExplicitSz = (int)SetExplicit(1, (word32)ukmOctetSz + kari->ukmSz,
8253 ukmExplicitSeq, 0);
8254 totalSz += ukmExplicitSz;
8255 }
8256
8257 /* Start of KeyEncryptionAlgorithmIdentifier */
8258
8259 /* KeyWrapAlgorithm */
8260 keyWrapAlgSz = (int)SetAlgoID(keyWrapOID, keyWrapAlg, oidKeyWrapType, 0);
8261 totalSz += keyWrapAlgSz;
8262
8263 /* KeyEncryptionAlgorithmIdentifier */
8264 keyEncryptAlgoIdSz = (int)SetAlgoID(keyAgreeOID, keyEncryptAlgoId,
8265 oidCmsKeyAgreeType, keyWrapAlgSz);
8266 totalSz += keyEncryptAlgoIdSz;
8267
8268 /* Start of OriginatorIdentifierOrKey */
8269
8270 /* recipient ECPoint, public key */
8271 XMEMSET(origPubKeyStr, 0, sizeof(origPubKeyStr)); /* no unused bits */
8272 origPubKeyStr[0] = ASN_BIT_STRING;
8273 origPubKeyStrSz = (int)SetLength(kari->senderKeyExportSz + 1,
8274 origPubKeyStr + 1) + 2;
8275 totalSz += (origPubKeyStrSz + (int)kari->senderKeyExportSz);
8276
8277 /* Originator AlgorithmIdentifier, params set to NULL for interop
8278 compatibility */
8279 origAlgIdSz = (int)SetAlgoID(ECDSAk, origAlgId, oidKeyType, 2);
8280 origAlgId[origAlgIdSz++] = ASN_TAG_NULL;
8281 origAlgId[origAlgIdSz++] = 0;
8282 totalSz += origAlgIdSz;
8283
8284 /* outer OriginatorPublicKey IMPLICIT [1] */
8285 origPubKeySeqSz = (int)SetImplicit(ASN_SEQUENCE, 1,
8286 (word32)(origAlgIdSz + origPubKeyStrSz +
8287 (int)kari->senderKeyExportSz), origPubKeySeq, 0);
8288 totalSz += origPubKeySeqSz;
8289
8290 /* outer OriginatorIdentifierOrKey IMPLICIT [0] */
8291 origIdOrKeySeqSz = (int)SetImplicit(ASN_SEQUENCE, 0,
8292 (word32)(origPubKeySeqSz + origAlgIdSz +
8293 origPubKeyStrSz + (int)kari->senderKeyExportSz),
8294 origIdOrKeySeq, 0);
8295 totalSz += origIdOrKeySeqSz;
8296
8297 /* version, always 3 */
8298 verSz = SetMyVersion(3, ver, 0);
8299 totalSz += verSz;
8300 recip->recipVersion = 3;
8301
8302 /* outer IMPLICIT [1] kari */
8303 kariSeqSz = (int)SetImplicit(ASN_SEQUENCE, 1, (word32)totalSz, kariSeq, 0);
8304 totalSz += kariSeqSz;
8305
8306 if (totalSz > MAX_RECIP_SZ) {
8307 WOLFSSL_MSG("KeyAgreeRecipientInfo output buffer too small");
8308 wc_PKCS7_KariFree(kari);
8309 WC_FREE_VAR_EX(encryptedKey, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
8310 XFREE(recip, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
8311 return BUFFER_E;
8312 }
8313
8314 XMEMCPY(recip->recip + idx, kariSeq, (word32)kariSeqSz);
8315 idx += (word32)kariSeqSz;
8316 XMEMCPY(recip->recip + idx, ver, (word32)verSz);
8317 idx += (word32)verSz;
8318
8319 XMEMCPY(recip->recip + idx, origIdOrKeySeq, (word32)origIdOrKeySeqSz);
8320 idx += (word32)origIdOrKeySeqSz;
8321 XMEMCPY(recip->recip + idx, origPubKeySeq, (word32)origPubKeySeqSz);
8322 idx += (word32)origPubKeySeqSz;
8323
8324 /* AlgorithmIdentifier with NULL parameter */
8325 XMEMCPY(recip->recip + idx, origAlgId, (word32)origAlgIdSz);
8326 idx += (word32)origAlgIdSz;
8327
8328 XMEMCPY(recip->recip + idx, origPubKeyStr, (word32)origPubKeyStrSz);
8329 idx += (word32)origPubKeyStrSz;
8330 /* ephemeral public key */
8331 XMEMCPY(recip->recip + idx, kari->senderKeyExport, kari->senderKeyExportSz);
8332 idx += kari->senderKeyExportSz;
8333
8334 if (kari->ukmSz > 0) {
8335 XMEMCPY(recip->recip + idx, ukmExplicitSeq, (word32)ukmExplicitSz);
8336 idx += (word32)ukmExplicitSz;
8337 XMEMCPY(recip->recip + idx, ukmOctetStr, (word32)ukmOctetSz);
8338 idx += (word32)ukmOctetSz;
8339 XMEMCPY(recip->recip + idx, kari->ukm, kari->ukmSz);
8340 idx += kari->ukmSz;
8341 }
8342
8343 XMEMCPY(recip->recip + idx, keyEncryptAlgoId, (word32)keyEncryptAlgoIdSz);
8344 idx += (word32)keyEncryptAlgoIdSz;
8345 XMEMCPY(recip->recip + idx, keyWrapAlg, (word32)keyWrapAlgSz);
8346 idx += (word32)keyWrapAlgSz;
8347
8348 XMEMCPY(recip->recip + idx, recipEncKeysSeq, (word32)recipEncKeysSeqSz);
8349 idx += (word32)recipEncKeysSeqSz;
8350 XMEMCPY(recip->recip + idx, recipEncKeySeq, (word32)recipEncKeySeqSz);
8351 idx += (word32)recipEncKeySeqSz;
8352 XMEMCPY(recip->recip + idx, recipKeyIdSeq, (word32)recipKeyIdSeqSz);
8353 idx += (word32)recipKeyIdSeqSz;
8354 XMEMCPY(recip->recip + idx, subjKeyIdOctet, (word32)subjKeyIdOctetSz);
8355 idx += (word32)subjKeyIdOctetSz;
8356 /* subject key id */
8357 XMEMCPY(recip->recip + idx, kari->decoded->extSubjKeyId, (word32)keyIdSize);
8358 idx += (word32)keyIdSize;
8359 XMEMCPY(recip->recip + idx, encryptedKeyOctet, (word32)encryptedKeyOctetSz);
8360 idx += (word32)encryptedKeyOctetSz;
8361 /* encrypted CEK */
8362 XMEMCPY(recip->recip + idx, encryptedKey, encryptedKeySz);
8363 idx += encryptedKeySz;
8364
8365 wc_PKCS7_KariFree(kari);
8366 WC_FREE_VAR_EX(encryptedKey, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
8367
8368 /* store recipient size */
8369 recip->recipSz = idx;
8370 recip->recipType = PKCS7_KARI;
8371
8372 /* add recipient to recip list */
8373 if (pkcs7->recipList == NULL) {
8374 pkcs7->recipList = recip;
8375 } else {
8376 lastRecip = pkcs7->recipList;
8377 while (lastRecip->next != NULL) {
8378 lastRecip = lastRecip->next;
8379 }
8380 lastRecip->next = recip;
8381 }
8382
8383 (void)options;
8384
8385 return (int)idx;
8386}
8387
8388#endif /* HAVE_ECC */
8389
8390#ifndef NO_RSA
8391
8392/* Encode and add CMS EnvelopedData KTRI (KeyTransRecipientInfo) RecipientInfo
8393 * to CMS/PKCS#7 EnvelopedData structure.
8394 *
8395 * Returns 0 on success, negative upon error */
8396int wc_PKCS7_AddRecipient_KTRI(wc_PKCS7* pkcs7, const byte* cert, word32 certSz,
8397 int options)
8398{
8399 Pkcs7EncodedRecip* recip = NULL;
8400 Pkcs7EncodedRecip* lastRecip = NULL;
8401
8402 WC_RNG rng;
8403 word32 idx = 0;
8404 word32 encryptedKeySz = 0;
8405 int keyIdSize;
8406
8407 int ret = 0, blockKeySz;
8408 int verSz = 0, issuerSz = 0, snSz = 0, keyEncAlgSz = 0;
8409 int issuerSeqSz = 0, recipSeqSz = 0, issuerSerialSeqSz = 0;
8410 int encKeyOctetStrSz;
8411 int sidType;
8412
8413 byte ver[MAX_VERSION_SZ];
8414 byte issuerSerialSeq[MAX_SEQ_SZ];
8415 byte recipSeq[MAX_SEQ_SZ];
8416 byte issuerSeq[MAX_SEQ_SZ];
8417 byte encKeyOctetStr[MAX_OCTET_STR_SZ];
8418
8419 byte issuerSKID[MAX_LENGTH_SZ];
8420 word32 issuerSKIDSz = 0;
8421
8422 byte* encryptedKey;
8423
8424#ifdef WOLFSSL_SMALL_STACK
8425 byte* serial;
8426 byte* keyAlgArray;
8427 RsaKey* pubKey;
8428 DecodedCert* decoded;
8429
8430 serial = (byte*)XMALLOC(MAX_SN_SZ, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
8431 keyAlgArray = (byte*)XMALLOC(MAX_ALGO_SZ, pkcs7->heap,
8432 DYNAMIC_TYPE_TMP_BUFFER);
8433 decoded = (DecodedCert*)XMALLOC(sizeof(DecodedCert), pkcs7->heap,
8434 DYNAMIC_TYPE_TMP_BUFFER);
8435
8436 if (decoded == NULL || serial == NULL || keyAlgArray == NULL) {
8437 XFREE(serial, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
8438 XFREE(keyAlgArray, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
8439 XFREE(decoded, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
8440 return MEMORY_E;
8441 }
8442#else
8443 byte serial[MAX_SN_SZ];
8444 byte keyAlgArray[MAX_ALGO_SZ];
8445 RsaKey pubKey[1];
8446 DecodedCert decoded[1];
8447#endif
8448
8449 /* Always allocate to ensure aligned use with RSA */
8450 encryptedKey = (byte*)XMALLOC(MAX_ENCRYPTED_KEY_SZ, pkcs7->heap,
8451 DYNAMIC_TYPE_WOLF_BIGINT);
8452 if (encryptedKey == NULL) {
8453 WC_FREE_VAR_EX(serial, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
8454 WC_FREE_VAR_EX(keyAlgArray, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
8455 WC_FREE_VAR_EX(decoded, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
8456 return MEMORY_E;
8457 }
8458
8459 encryptedKeySz = MAX_ENCRYPTED_KEY_SZ;
8460 XMEMSET(encryptedKey, 0, encryptedKeySz);
8461
8462 /* default to IssuerAndSerialNumber if not set */
8463 if (pkcs7->sidType != 0) {
8464 sidType = pkcs7->sidType;
8465 } else {
8466 sidType = CMS_ISSUER_AND_SERIAL_NUMBER;
8467 }
8468
8469 /* allow options to override SubjectIdentifier type if set */
8470 if (options & CMS_SKID) {
8471 sidType = CMS_SKID;
8472 } else if (options & CMS_ISSUER_AND_SERIAL_NUMBER) {
8473 sidType = CMS_ISSUER_AND_SERIAL_NUMBER;
8474 }
8475
8476 /* allocate recipient struct */
8477 recip = (Pkcs7EncodedRecip*)XMALLOC(sizeof(Pkcs7EncodedRecip), pkcs7->heap,
8478 DYNAMIC_TYPE_PKCS7);
8479 if (recip == NULL) {
8480 WC_FREE_VAR_EX(serial, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
8481 WC_FREE_VAR_EX(keyAlgArray, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
8482 WC_FREE_VAR_EX(decoded, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
8483 XFREE(encryptedKey, pkcs7->heap, DYNAMIC_TYPE_WOLF_BIGINT);
8484 return MEMORY_E;
8485 }
8486 XMEMSET(recip, 0, sizeof(Pkcs7EncodedRecip));
8487
8488 /* get key size for content-encryption key based on algorithm */
8489 blockKeySz = wc_PKCS7_GetOIDKeySize(pkcs7->encryptOID);
8490 if (blockKeySz < 0) {
8491 WC_FREE_VAR_EX(serial, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
8492 WC_FREE_VAR_EX(keyAlgArray, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
8493 WC_FREE_VAR_EX(decoded, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
8494 XFREE(encryptedKey, pkcs7->heap, DYNAMIC_TYPE_WOLF_BIGINT);
8495 XFREE(recip, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
8496 return blockKeySz;
8497 }
8498
8499 /* generate random content encryption key, if needed */
8500 ret = PKCS7_GenerateContentEncryptionKey(pkcs7, (word32)blockKeySz);
8501 if (ret < 0) {
8502 WC_FREE_VAR_EX(serial, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
8503 WC_FREE_VAR_EX(keyAlgArray, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
8504 WC_FREE_VAR_EX(decoded, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
8505 XFREE(encryptedKey, pkcs7->heap, DYNAMIC_TYPE_WOLF_BIGINT);
8506 XFREE(recip, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
8507 return ret;
8508 }
8509
8510 InitDecodedCert(decoded, cert, certSz, pkcs7->heap);
8511 ret = ParseCert(decoded, CA_TYPE, NO_VERIFY, 0);
8512 if (ret < 0) {
8513 FreeDecodedCert(decoded);
8514 WC_FREE_VAR_EX(serial, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
8515 WC_FREE_VAR_EX(keyAlgArray, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
8516 WC_FREE_VAR_EX(decoded, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
8517 XFREE(encryptedKey, pkcs7->heap, DYNAMIC_TYPE_WOLF_BIGINT);
8518 XFREE(recip, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
8519 return ret;
8520 }
8521
8522#if defined(WOLFSSL_SM2) && defined(WOLFSSL_SM3)
8523 keyIdSize = wc_HashGetDigestSize(wc_HashTypeConvert(HashIdAlg(
8524 decoded->signatureOID)));
8525#else
8526 keyIdSize = KEYID_SIZE;
8527#endif
8528
8529 if (sidType == CMS_ISSUER_AND_SERIAL_NUMBER) {
8530
8531 /* version, must be 0 for IssuerAndSerialNumber */
8532 verSz = SetMyVersion(0, ver, 0);
8533 recip->recipVersion = 0;
8534
8535 /* IssuerAndSerialNumber */
8536 if (decoded->issuerRaw == NULL || decoded->issuerRawLen == 0) {
8537 WOLFSSL_MSG("DecodedCert lacks raw issuer pointer and length");
8538 FreeDecodedCert(decoded);
8539 WC_FREE_VAR_EX(serial, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
8540 WC_FREE_VAR_EX(keyAlgArray, pkcs7->heap,
8541 DYNAMIC_TYPE_TMP_BUFFER);
8542 WC_FREE_VAR_EX(decoded, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
8543 XFREE(encryptedKey, pkcs7->heap, DYNAMIC_TYPE_WOLF_BIGINT);
8544 XFREE(recip, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
8545 return -1;
8546 }
8547 issuerSz = decoded->issuerRawLen;
8548 issuerSeqSz = (int)SetSequence((word32)issuerSz, issuerSeq);
8549
8550 if (decoded->serialSz == 0) {
8551 WOLFSSL_MSG("DecodedCert missing serial number");
8552 FreeDecodedCert(decoded);
8553 WC_FREE_VAR_EX(serial, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
8554 WC_FREE_VAR_EX(keyAlgArray, pkcs7->heap,
8555 DYNAMIC_TYPE_TMP_BUFFER);
8556 WC_FREE_VAR_EX(decoded, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
8557 XFREE(encryptedKey, pkcs7->heap, DYNAMIC_TYPE_WOLF_BIGINT);
8558 XFREE(recip, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
8559 return -1;
8560 }
8561 snSz = SetSerialNumber(decoded->serial, (word32)decoded->serialSz,
8562 serial, MAX_SN_SZ, MAX_SN_SZ);
8563 if (snSz < 0) {
8564 WOLFSSL_MSG("Error setting the serial number");
8565 FreeDecodedCert(decoded);
8566 WC_FREE_VAR_EX(serial, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
8567 WC_FREE_VAR_EX(keyAlgArray, pkcs7->heap,
8568 DYNAMIC_TYPE_TMP_BUFFER);
8569 WC_FREE_VAR_EX(decoded, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
8570 XFREE(encryptedKey, pkcs7->heap, DYNAMIC_TYPE_WOLF_BIGINT);
8571 XFREE(recip, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
8572 return -1;
8573 }
8574 issuerSerialSeqSz = (int)SetSequence((word32)(issuerSeqSz + issuerSz +
8575 snSz), issuerSerialSeq);
8576 } else if (sidType == CMS_SKID) {
8577
8578 /* version, must be 2 for SubjectKeyIdentifier */
8579 verSz = SetMyVersion(2, ver, 0);
8580 recip->recipVersion = 2;
8581
8582 issuerSKIDSz = SetLength((word32)keyIdSize, issuerSKID);
8583 } else {
8584 FreeDecodedCert(decoded);
8585 WC_FREE_VAR_EX(serial, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
8586 WC_FREE_VAR_EX(keyAlgArray, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
8587 WC_FREE_VAR_EX(decoded, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
8588 XFREE(encryptedKey, pkcs7->heap, DYNAMIC_TYPE_WOLF_BIGINT);
8589 XFREE(recip, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
8590 return PKCS7_RECIP_E;
8591 }
8592
8593 pkcs7->publicKeyOID = decoded->keyOID;
8594
8595 /* KeyEncryptionAlgorithmIdentifier, only support RSA now */
8596 if (pkcs7->publicKeyOID != RSAk
8597#ifdef WC_RSA_PSS
8598 && pkcs7->publicKeyOID != RSAPSSk
8599#endif
8600 ) {
8601 FreeDecodedCert(decoded);
8602 WC_FREE_VAR_EX(serial, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
8603 WC_FREE_VAR_EX(keyAlgArray, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
8604 WC_FREE_VAR_EX(decoded, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
8605 XFREE(encryptedKey, pkcs7->heap, DYNAMIC_TYPE_WOLF_BIGINT);
8606 XFREE(recip, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
8607 return ALGO_ID_E;
8608 }
8609
8610 keyEncAlgSz = (int)SetAlgoID(RSAk, keyAlgArray, oidKeyType, 0);
8611 if (keyEncAlgSz == 0) {
8612 FreeDecodedCert(decoded);
8613 WC_FREE_VAR_EX(serial, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
8614 WC_FREE_VAR_EX(keyAlgArray, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
8615 WC_FREE_VAR_EX(decoded, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
8616 XFREE(encryptedKey, pkcs7->heap, DYNAMIC_TYPE_WOLF_BIGINT);
8617 XFREE(recip, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
8618 return BAD_FUNC_ARG;
8619 }
8620
8621#ifdef WOLFSSL_SMALL_STACK
8622 pubKey = (RsaKey*)XMALLOC(sizeof(RsaKey), pkcs7->heap,
8623 DYNAMIC_TYPE_TMP_BUFFER);
8624 if (pubKey == NULL) {
8625 FreeDecodedCert(decoded);
8626 XFREE(serial, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
8627 XFREE(keyAlgArray, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
8628 XFREE(encryptedKey, pkcs7->heap, DYNAMIC_TYPE_WOLF_BIGINT);
8629 XFREE(decoded, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
8630 XFREE(recip, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
8631 return MEMORY_E;
8632 }
8633#endif
8634
8635 /* EncryptedKey */
8636 ret = wc_InitRsaKey_ex(pubKey, pkcs7->heap, pkcs7->devId);
8637 if (ret != 0) {
8638 FreeDecodedCert(decoded);
8639 WC_FREE_VAR_EX(pubKey, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
8640 WC_FREE_VAR_EX(serial, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
8641 WC_FREE_VAR_EX(keyAlgArray, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
8642 WC_FREE_VAR_EX(decoded, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
8643 XFREE(encryptedKey, pkcs7->heap, DYNAMIC_TYPE_WOLF_BIGINT);
8644 XFREE(recip, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
8645 return ret;
8646 }
8647
8648 if (wc_RsaPublicKeyDecode(decoded->publicKey, &idx, pubKey,
8649 decoded->pubKeySize) < 0) {
8650 WOLFSSL_MSG("ASN RSA key decode error");
8651 wc_FreeRsaKey(pubKey);
8652 FreeDecodedCert(decoded);
8653 WC_FREE_VAR_EX(pubKey, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
8654 WC_FREE_VAR_EX(serial, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
8655 WC_FREE_VAR_EX(keyAlgArray, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
8656 WC_FREE_VAR_EX(decoded, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
8657 XFREE(encryptedKey, pkcs7->heap, DYNAMIC_TYPE_WOLF_BIGINT);
8658 XFREE(recip, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
8659 return PUBLIC_KEY_E;
8660 }
8661
8662 ret = wc_InitRng_ex(&rng, pkcs7->heap, pkcs7->devId);
8663 if (ret != 0) {
8664 wc_FreeRsaKey(pubKey);
8665 FreeDecodedCert(decoded);
8666 WC_FREE_VAR_EX(pubKey, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
8667 WC_FREE_VAR_EX(serial, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
8668 WC_FREE_VAR_EX(keyAlgArray, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
8669 WC_FREE_VAR_EX(decoded, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
8670 XFREE(encryptedKey, pkcs7->heap, DYNAMIC_TYPE_WOLF_BIGINT);
8671 XFREE(recip, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
8672 return MEMORY_E;
8673 }
8674
8675
8676#ifdef WOLFSSL_ASYNC_CRYPT
8677 /* Currently the call to RSA public encrypt here is blocking @TODO */
8678 do {
8679 ret = wc_AsyncWait(ret, &pubKey->asyncDev, WC_ASYNC_FLAG_CALL_AGAIN);
8680 if (ret >= 0)
8681#endif
8682 {
8683 ret = wc_RsaPublicEncrypt(pkcs7->cek, pkcs7->cekSz, encryptedKey,
8684 encryptedKeySz, pubKey, &rng);
8685 }
8686#ifdef WOLFSSL_ASYNC_CRYPT
8687 } while (ret == WC_NO_ERR_TRACE(WC_PENDING_E));
8688#endif
8689 wc_FreeRsaKey(pubKey);
8690 wc_FreeRng(&rng);
8691
8692 WC_FREE_VAR_EX(pubKey, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
8693
8694 if (ret < 0) {
8695 WOLFSSL_MSG("RSA Public Encrypt failed");
8696 FreeDecodedCert(decoded);
8697 WC_FREE_VAR_EX(serial, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
8698 WC_FREE_VAR_EX(keyAlgArray, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
8699 WC_FREE_VAR_EX(decoded, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
8700 XFREE(encryptedKey, pkcs7->heap, DYNAMIC_TYPE_WOLF_BIGINT);
8701 XFREE(recip, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
8702 return ret;
8703 }
8704 encryptedKeySz = (word32)ret;
8705
8706 encKeyOctetStrSz = (int)SetOctetString(encryptedKeySz, encKeyOctetStr);
8707
8708 /* RecipientInfo */
8709 if (sidType == CMS_ISSUER_AND_SERIAL_NUMBER) {
8710 int recipLen = verSz + (int)issuerSerialSeqSz + issuerSeqSz +
8711 issuerSz + snSz + keyEncAlgSz + encKeyOctetStrSz +
8712 (int)encryptedKeySz;
8713 recipSeqSz = (int)SetSequence((word32)recipLen, recipSeq);
8714
8715 if ((recipSeqSz + recipLen) > MAX_RECIP_SZ) {
8716 WOLFSSL_MSG("RecipientInfo output buffer too small");
8717 FreeDecodedCert(decoded);
8718 WC_FREE_VAR_EX(serial, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
8719 WC_FREE_VAR_EX(keyAlgArray, pkcs7->heap,
8720 DYNAMIC_TYPE_TMP_BUFFER);
8721 WC_FREE_VAR_EX(decoded, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
8722 XFREE(encryptedKey, pkcs7->heap, DYNAMIC_TYPE_WOLF_BIGINT);
8723 XFREE(recip, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
8724 return BUFFER_E;
8725 }
8726
8727 } else {
8728 int recipLen = verSz + ASN_TAG_SZ + (int)issuerSKIDSz + keyIdSize +
8729 keyEncAlgSz + encKeyOctetStrSz + (int)encryptedKeySz;
8730 recipSeqSz = (int)SetSequence((word32)recipLen, recipSeq);
8731 if ((recipSeqSz + recipLen) > MAX_RECIP_SZ) {
8732 WOLFSSL_MSG("RecipientInfo output buffer too small");
8733 FreeDecodedCert(decoded);
8734 WC_FREE_VAR_EX(serial, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
8735 WC_FREE_VAR_EX(keyAlgArray, pkcs7->heap,
8736 DYNAMIC_TYPE_TMP_BUFFER);
8737 WC_FREE_VAR_EX(decoded, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
8738 XFREE(encryptedKey, pkcs7->heap, DYNAMIC_TYPE_WOLF_BIGINT);
8739 XFREE(recip, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
8740 return BUFFER_E;
8741 }
8742 }
8743
8744 idx = 0;
8745 XMEMCPY(recip->recip + idx, recipSeq, (word32)recipSeqSz);
8746 idx += (word32)recipSeqSz;
8747 XMEMCPY(recip->recip + idx, ver, (word32)verSz);
8748 idx += (word32)verSz;
8749 if (sidType == CMS_ISSUER_AND_SERIAL_NUMBER) {
8750 XMEMCPY(recip->recip + idx, issuerSerialSeq, (word32)issuerSerialSeqSz);
8751 idx += (word32)issuerSerialSeqSz;
8752 XMEMCPY(recip->recip + idx, issuerSeq, (word32)issuerSeqSz);
8753 idx += (word32)issuerSeqSz;
8754 XMEMCPY(recip->recip + idx, decoded->issuerRaw, (word32)issuerSz);
8755 idx += (word32)issuerSz;
8756 XMEMCPY(recip->recip + idx, serial, (word32)snSz);
8757 idx += (word32)snSz;
8758 } else {
8759 recip->recip[idx] = ASN_CONTEXT_SPECIFIC;
8760 idx += ASN_TAG_SZ;
8761 XMEMCPY(recip->recip + idx, issuerSKID, issuerSKIDSz);
8762 idx += issuerSKIDSz;
8763 XMEMCPY(recip->recip + idx, pkcs7->issuerSubjKeyId, (word32)keyIdSize);
8764 idx += (word32)keyIdSize;
8765 }
8766 XMEMCPY(recip->recip + idx, keyAlgArray, (word32)keyEncAlgSz);
8767 idx += (word32)keyEncAlgSz;
8768 XMEMCPY(recip->recip + idx, encKeyOctetStr, (word32)encKeyOctetStrSz);
8769 idx += (word32)encKeyOctetStrSz;
8770 XMEMCPY(recip->recip + idx, encryptedKey, encryptedKeySz);
8771 idx += encryptedKeySz;
8772
8773 FreeDecodedCert(decoded);
8774
8775 WC_FREE_VAR_EX(serial, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
8776 WC_FREE_VAR_EX(keyAlgArray, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
8777 WC_FREE_VAR_EX(decoded, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
8778 XFREE(encryptedKey, pkcs7->heap, DYNAMIC_TYPE_WOLF_BIGINT);
8779
8780 /* store recipient size */
8781 recip->recipSz = idx;
8782 recip->recipType = PKCS7_KTRI;
8783
8784 /* add recipient to recip list */
8785 if (pkcs7->recipList == NULL) {
8786 pkcs7->recipList = recip;
8787 } else {
8788 lastRecip = pkcs7->recipList;
8789 while (lastRecip->next != NULL) {
8790 lastRecip = lastRecip->next;
8791 }
8792 lastRecip->next = recip;
8793 }
8794
8795 return (int)idx;
8796}
8797
8798#endif /* !NO_RSA */
8799
8800/* abstraction for writing out PKCS7 bundle during creation
8801 returns 0 on success
8802 */
8803int wc_PKCS7_WriteOut(wc_PKCS7* pkcs7, byte* output, const byte* input,
8804 word32 inputSz)
8805{
8806 int ret = 0;
8807
8808 if (inputSz == 0)
8809 return 0;
8810
8811 if (input == NULL) {
8812 WOLFSSL_MSG("Internal error, trying to write out NULL buffer");
8813 return -1;
8814 }
8815
8816#ifdef ASN_BER_TO_DER
8817 if (pkcs7->streamOutCb) {
8818 ret = pkcs7->streamOutCb(pkcs7, input, inputSz, pkcs7->streamCtx);
8819 /* sanity check on user provided ret value */
8820 if (ret < 0) {
8821 WOLFSSL_MSG("Return value error from stream out callback");
8822 ret = BUFFER_E;
8823 }
8824 }
8825 else
8826#endif
8827 if (output) {
8828 XMEMCPY(output, input, inputSz);
8829 }
8830 else {
8831 WOLFSSL_MSG("No way provided to output bundle");
8832 ret = BUFFER_E;
8833 }
8834
8835 (void)pkcs7;
8836 return ret;
8837}
8838
8839
8840/* encrypt content using encryptOID algo */
8841static int wc_PKCS7_EncryptContent(wc_PKCS7* pkcs7, int encryptOID,
8842 const byte* key, int keySz,
8843 const byte* iv, int ivSz,
8844 const byte* aad, word32 aadSz,
8845 byte* authTag, word32 authTagSz,
8846 const byte* in, int inSz,
8847 byte* out)
8848{
8849 int ret;
8850#ifndef NO_AES
8851 WC_DECLARE_VAR(aes, Aes, 1, 0);
8852#endif
8853#ifndef NO_DES3
8854 Des des;
8855 Des3 des3;
8856#endif
8857 int devId = pkcs7->devId;
8858 void* heap = pkcs7->heap;
8859
8860 if (key == NULL || iv == NULL)
8861 return BAD_FUNC_ARG;
8862
8863#ifdef ASN_BER_TO_DER
8864 if ((in == NULL && pkcs7->getContentCb == NULL) ||
8865 (out == NULL && pkcs7->streamOutCb == NULL)) {
8866 WOLFSSL_MSG("No input or output set for encrypt");
8867 return BAD_FUNC_ARG;
8868 }
8869#else
8870 if (in == NULL || out == NULL)
8871 return BAD_FUNC_ARG;
8872#endif
8873
8874 switch (encryptOID) {
8875#ifndef NO_AES
8876 #ifdef HAVE_AES_CBC
8877 #ifdef WOLFSSL_AES_128
8878 case AES128CBCb:
8879 #endif
8880 #ifdef WOLFSSL_AES_192
8881 case AES192CBCb:
8882 #endif
8883 #ifdef WOLFSSL_AES_256
8884 case AES256CBCb:
8885 #endif
8886 if (
8887 #ifdef WOLFSSL_AES_128
8888 (encryptOID == AES128CBCb && keySz != 16 ) ||
8889 #endif
8890 #ifdef WOLFSSL_AES_192
8891 (encryptOID == AES192CBCb && keySz != 24 ) ||
8892 #endif
8893 #ifdef WOLFSSL_AES_256
8894 (encryptOID == AES256CBCb && keySz != 32 ) ||
8895 #endif
8896 (ivSz != WC_AES_BLOCK_SIZE) )
8897 return BAD_FUNC_ARG;
8898
8899#ifdef WOLFSSL_SMALL_STACK
8900 if ((aes = (Aes *)XMALLOC(sizeof *aes, NULL,
8901 DYNAMIC_TYPE_AES)) == NULL)
8902 return MEMORY_E;
8903#endif
8904 ret = wc_AesInit(aes, heap, devId);
8905 if (ret == 0) {
8906 ret = wc_AesSetKey(aes, key, (word32)keySz, iv, AES_ENCRYPTION);
8907 if (ret == 0) {
8908 ret = wc_PKCS7_EncodeContentStream(pkcs7, NULL, aes, in,
8909 inSz, out, WC_CIPHER_AES_CBC);
8910 }
8911 wc_AesFree(aes);
8912 }
8913 WC_FREE_VAR_EX(aes, NULL, DYNAMIC_TYPE_AES);
8914 break;
8915 #endif /* HAVE_AES_CBC */
8916 #ifdef HAVE_AESGCM
8917 #ifdef WOLFSSL_AES_128
8918 case AES128GCMb:
8919 #endif
8920 #ifdef WOLFSSL_AES_192
8921 case AES192GCMb:
8922 #endif
8923 #ifdef WOLFSSL_AES_256
8924 case AES256GCMb:
8925 #endif
8926 #if defined(WOLFSSL_AES_128) || defined(WOLFSSL_AES_192) || \
8927 defined(WOLFSSL_AES_256)
8928 if (authTag == NULL)
8929 return BAD_FUNC_ARG;
8930
8931#ifdef WOLFSSL_SMALL_STACK
8932 if ((aes = (Aes *)XMALLOC(sizeof *aes, NULL,
8933 DYNAMIC_TYPE_AES)) == NULL)
8934 return MEMORY_E;
8935#endif
8936 ret = wc_AesInit(aes, heap, devId);
8937 if (ret == 0) {
8938 ret = wc_AesGcmSetKey(aes, key, (word32)keySz);
8939 if (ret == 0) {
8940 #ifndef WOLFSSL_AESGCM_STREAM
8941 if (pkcs7->encodeStream) {
8942 WOLFSSL_MSG("Not AES-GCM stream support compiled in");
8943 ret = NOT_COMPILED_IN;
8944 }
8945 else {
8946 ret = wc_AesGcmEncrypt(aes, out, in, (word32)inSz, iv,
8947 (word32)ivSz, authTag, authTagSz, aad, aadSz);
8948 #ifdef WOLFSSL_ASYNC_CRYPT
8949 /* async encrypt not available here, so block till done
8950 */
8951 ret = wc_AsyncWait(ret, &aes->asyncDev,
8952 WC_ASYNC_FLAG_NONE);
8953 #endif
8954 }
8955 #else
8956 ret = wc_AesGcmEncryptInit(aes, key, (word32)keySz, iv,
8957 (word32)ivSz);
8958 if (ret == 0) {
8959 ret = wc_AesGcmEncryptUpdate(aes, NULL, NULL, 0, aad,
8960 aadSz);
8961 }
8962 if (ret == 0) {
8963 ret = wc_PKCS7_EncodeContentStream(pkcs7, NULL, aes, in,
8964 inSz, out, WC_CIPHER_AES_GCM);
8965 }
8966
8967 if (ret == 0) {
8968 ret = wc_AesGcmEncryptFinal(aes, authTag, authTagSz);
8969 }
8970 #endif
8971 }
8972 wc_AesFree(aes);
8973 }
8974 WC_FREE_VAR_EX(aes, NULL, DYNAMIC_TYPE_AES);
8975 break;
8976 #endif
8977 #endif /* HAVE_AESGCM */
8978 #ifdef HAVE_AESCCM
8979 #ifdef WOLFSSL_AES_128
8980 case AES128CCMb:
8981 #endif
8982 #ifdef WOLFSSL_AES_192
8983 case AES192CCMb:
8984 #endif
8985 #ifdef WOLFSSL_AES_256
8986 case AES256CCMb:
8987 #endif
8988 #if defined(WOLFSSL_AES_128) || defined(WOLFSSL_AES_192) || \
8989 defined(WOLFSSL_AES_256)
8990 if (authTag == NULL)
8991 return BAD_FUNC_ARG;
8992
8993 if (pkcs7->encodeStream) {
8994 WOLFSSL_MSG("Streaming encoding not supported with AES-CCM");
8995 return BAD_FUNC_ARG;
8996 }
8997
8998#ifdef WOLFSSL_SMALL_STACK
8999 if ((aes = (Aes *)XMALLOC(sizeof *aes, NULL,
9000 DYNAMIC_TYPE_AES)) == NULL)
9001 return MEMORY_E;
9002#endif
9003 ret = wc_AesInit(aes, heap, devId);
9004 if (ret == 0) {
9005 ret = wc_AesCcmSetKey(aes, key, (word32)keySz);
9006 if (ret == 0) {
9007 ret = wc_AesCcmEncrypt(aes, out, in, (word32)inSz, iv,
9008 (word32)ivSz, authTag, authTagSz,
9009 aad, aadSz);
9010 #ifdef WOLFSSL_ASYNC_CRYPT
9011 /* async encrypt not available here, so block till done */
9012 ret = wc_AsyncWait(ret, &aes->asyncDev, WC_ASYNC_FLAG_NONE);
9013 #endif
9014 }
9015 wc_AesFree(aes);
9016 }
9017 WC_FREE_VAR_EX(aes, NULL, DYNAMIC_TYPE_AES);
9018 break;
9019 #endif
9020 #endif /* HAVE_AESCCM */
9021#endif /* !NO_AES */
9022#ifndef NO_DES3
9023 case DESb:
9024 if (keySz != DES_KEYLEN || ivSz != DES_BLOCK_SIZE)
9025 return BAD_FUNC_ARG;
9026
9027 if (pkcs7->encodeStream) {
9028 WOLFSSL_MSG("Streaming encoding not supported with DES3");
9029 return BAD_FUNC_ARG;
9030 }
9031
9032 ret = wc_Des_SetKey(&des, key, iv, DES_ENCRYPTION);
9033 if (ret == 0)
9034 ret = wc_Des_CbcEncrypt(&des, out, in, (word32)inSz);
9035
9036 break;
9037
9038 case DES3b:
9039 if (keySz != DES3_KEYLEN || ivSz != DES_BLOCK_SIZE)
9040 return BAD_FUNC_ARG;
9041
9042 if (pkcs7->encodeStream) {
9043 WOLFSSL_MSG("Streaming encoding not supported with DES3");
9044 return BAD_FUNC_ARG;
9045 }
9046
9047 ret = wc_Des3Init(&des3, heap, devId);
9048 if (ret == 0) {
9049 ret = wc_Des3_SetKey(&des3, key, iv, DES_ENCRYPTION);
9050 if (ret == 0) {
9051 ret = wc_Des3_CbcEncrypt(&des3, out, in, (word32)inSz);
9052 #ifdef WOLFSSL_ASYNC_CRYPT
9053 /* async encrypt not available here, so block till done */
9054 ret = wc_AsyncWait(ret, &des3.asyncDev, WC_ASYNC_FLAG_NONE);
9055 #endif
9056 }
9057 wc_Des3Free(&des3);
9058 }
9059 break;
9060#endif /* !NO_DES3 */
9061 default:
9062 WOLFSSL_MSG("Unsupported content cipher type");
9063 return ALGO_ID_E;
9064 };
9065
9066#if defined(NO_AES) || (!defined(HAVE_AESGCM) && !defined(HAVE_AESCCM))
9067 (void)authTag;
9068 (void)authTagSz;
9069 (void)aad;
9070 (void)aadSz;
9071#endif
9072 return ret;
9073}
9074
9075
9076static int wc_PKCS7_DecryptContentInit(wc_PKCS7* pkcs7, word32 encryptOID,
9077 const byte* key, word32 keySz, const byte* iv, int ivSz,
9078 int devId, void* heap)
9079{
9080 int ret;
9081#ifndef NO_AES
9082 Aes *aes;
9083#endif
9084#ifndef NO_DES3
9085 Des *des;
9086 Des3 *des3;
9087#endif
9088
9089 if (iv == NULL)
9090 return BAD_FUNC_ARG;
9091
9092 if (key == NULL)
9093 return BAD_FUNC_ARG;
9094
9095 switch (encryptOID) {
9096#ifndef NO_AES
9097 #ifdef HAVE_AES_CBC
9098 #ifdef WOLFSSL_AES_128
9099 case AES128CBCb:
9100 #endif
9101 #ifdef WOLFSSL_AES_192
9102 case AES192CBCb:
9103 #endif
9104 #ifdef WOLFSSL_AES_256
9105 case AES256CBCb:
9106 #endif
9107 if (
9108 #ifdef WOLFSSL_AES_128
9109 (encryptOID == AES128CBCb && keySz != 16 ) ||
9110 #endif
9111 #ifdef WOLFSSL_AES_192
9112 (encryptOID == AES192CBCb && keySz != 24 ) ||
9113 #endif
9114 #ifdef WOLFSSL_AES_256
9115 (encryptOID == AES256CBCb && keySz != 32 ) ||
9116 #endif
9117 (ivSz != WC_AES_BLOCK_SIZE) )
9118 return BAD_FUNC_ARG;
9119
9120 pkcs7->decryptKey.aes = (Aes *)XMALLOC(sizeof *aes, NULL,
9121 DYNAMIC_TYPE_AES);
9122 aes = pkcs7->decryptKey.aes;
9123 if (aes == NULL)
9124 return MEMORY_E;
9125 ret = wc_AesInit(aes, heap, devId);
9126 if (ret == 0) {
9127 ret = wc_AesSetKey(aes, key, (word32)keySz, iv, AES_DECRYPTION);
9128 }
9129 break;
9130
9131 #endif /* HAVE_AES_CBC */
9132 #ifdef HAVE_AESGCM
9133 #ifdef WOLFSSL_AES_128
9134 case AES128GCMb:
9135 #endif
9136 #ifdef WOLFSSL_AES_192
9137 case AES192GCMb:
9138 #endif
9139 #ifdef WOLFSSL_AES_256
9140 case AES256GCMb:
9141 #endif
9142 #if defined(WOLFSSL_AES_128) || defined(WOLFSSL_AES_192) || \
9143 defined(WOLFSSL_AES_256)
9144 pkcs7->decryptKey.aes = (Aes *)XMALLOC(sizeof *aes, NULL,
9145 DYNAMIC_TYPE_AES);
9146 aes = pkcs7->decryptKey.aes;
9147 if (aes == NULL)
9148 return MEMORY_E;
9149 ret = wc_AesInit(aes, heap, devId);
9150 if (ret == 0) {
9151 ret = wc_AesGcmSetKey(aes, key, (word32)keySz);
9152 }
9153 break;
9154 #endif
9155 #endif /* HAVE_AESGCM */
9156 #ifdef HAVE_AESCCM
9157 #ifdef WOLFSSL_AES_128
9158 case AES128CCMb:
9159 #endif
9160 #ifdef WOLFSSL_AES_192
9161 case AES192CCMb:
9162 #endif
9163 #ifdef WOLFSSL_AES_256
9164 case AES256CCMb:
9165 #endif
9166 #if defined(WOLFSSL_AES_128) || defined(WOLFSSL_AES_192) || \
9167 defined(WOLFSSL_AES_256)
9168 pkcs7->decryptKey.aes = (Aes *)XMALLOC(sizeof *aes, NULL,
9169 DYNAMIC_TYPE_AES);
9170 aes = pkcs7->decryptKey.aes;
9171 if (aes == NULL)
9172 return MEMORY_E;
9173 ret = wc_AesInit(aes, heap, devId);
9174 if (ret == 0) {
9175 ret = wc_AesCcmSetKey(aes, key, (word32)keySz);
9176 }
9177 break;
9178 #endif
9179 #endif /* HAVE_AESCCM */
9180#endif /* !NO_AES */
9181#ifndef NO_DES3
9182 case DESb:
9183 if (keySz != DES_KEYLEN || ivSz != DES_BLOCK_SIZE)
9184 return BAD_FUNC_ARG;
9185
9186 pkcs7->decryptKey.des = (Des *)XMALLOC(sizeof *des, NULL,
9187 DYNAMIC_TYPE_PKCS7);
9188 des = pkcs7->decryptKey.des;
9189 if (des == NULL) {
9190 return MEMORY_E;
9191 }
9192 ret = wc_Des_SetKey(des, key, iv, DES_DECRYPTION);
9193 break;
9194 case DES3b:
9195 if (keySz != DES3_KEYLEN || ivSz != DES_BLOCK_SIZE)
9196 return BAD_FUNC_ARG;
9197
9198 pkcs7->decryptKey.des3 = (Des3 *)XMALLOC(sizeof *des3, NULL,
9199 DYNAMIC_TYPE_PKCS7);
9200 des3 = pkcs7->decryptKey.des3;
9201 if (des3 == NULL) {
9202 return MEMORY_E;
9203 }
9204 ret = wc_Des3Init(des3, heap, devId);
9205 if (ret == 0) {
9206 ret = wc_Des3_SetKey(des3, key, iv, DES_DECRYPTION);
9207 }
9208
9209 break;
9210#endif /* !NO_DES3 */
9211 default:
9212 WOLFSSL_MSG("Unsupported content cipher type");
9213 return ALGO_ID_E;
9214 };
9215
9216 return ret;
9217}
9218
9219
9220/* Only does decryption of content using encryptOID algo and already set keys
9221 * returns 0 on success */
9222static int wc_PKCS7_DecryptContentEx(wc_PKCS7* pkcs7, word32 encryptOID,
9223 const byte* iv, int ivSz, const byte* aad, word32 aadSz,
9224 const byte* authTag, word32 authTagSz, const byte* in, int inSz, byte* out)
9225{
9226 int ret;
9227
9228 if (in == NULL
9229 #ifdef ASN_BER_TO_DER
9230 && pkcs7->getContentCb == NULL
9231 #endif
9232 ) {
9233 return BAD_FUNC_ARG;
9234 }
9235
9236 switch (encryptOID) {
9237#ifndef NO_AES
9238 #ifdef HAVE_AES_CBC
9239 #ifdef WOLFSSL_AES_128
9240 case AES128CBCb:
9241 #endif
9242 #ifdef WOLFSSL_AES_192
9243 case AES192CBCb:
9244 #endif
9245 #ifdef WOLFSSL_AES_256
9246 case AES256CBCb:
9247 #endif
9248 ret = wc_AesCbcDecrypt(pkcs7->decryptKey.aes, out, in,
9249 (word32)inSz);
9250 #ifdef WOLFSSL_ASYNC_CRYPT
9251 /* async decrypt not available here, so block till done */
9252 ret = wc_AsyncWait(ret, &pkcs7->decryptKey.aes->asyncDev,
9253 WC_ASYNC_FLAG_NONE);
9254 #endif
9255 break;
9256 #endif /* HAVE_AES_CBC */
9257 #ifdef HAVE_AESGCM
9258 #ifdef WOLFSSL_AES_128
9259 case AES128GCMb:
9260 #endif
9261 #ifdef WOLFSSL_AES_192
9262 case AES192GCMb:
9263 #endif
9264 #ifdef WOLFSSL_AES_256
9265 case AES256GCMb:
9266 #endif
9267 #if defined(WOLFSSL_AES_128) || defined(WOLFSSL_AES_192) || \
9268 defined(WOLFSSL_AES_256)
9269 if (authTag == NULL)
9270 return BAD_FUNC_ARG;
9271
9272 ret = wc_AesGcmDecrypt(pkcs7->decryptKey.aes, out, in,
9273 (word32)inSz, iv, (word32)ivSz, authTag, authTagSz,
9274 aad, aadSz);
9275 #ifdef WOLFSSL_ASYNC_CRYPT
9276 /* async decrypt not available here, so block till done */
9277 ret = wc_AsyncWait(ret, &pkcs7->decryptKey.aes->asyncDev,
9278 WC_ASYNC_FLAG_NONE);
9279 #endif
9280 break;
9281 #endif
9282 #endif /* HAVE_AESGCM */
9283 #ifdef HAVE_AESCCM
9284 #ifdef WOLFSSL_AES_128
9285 case AES128CCMb:
9286 #endif
9287 #ifdef WOLFSSL_AES_192
9288 case AES192CCMb:
9289 #endif
9290 #ifdef WOLFSSL_AES_256
9291 case AES256CCMb:
9292 #endif
9293 ret = wc_AesCcmDecrypt(pkcs7->decryptKey.aes, out, in,
9294 (word32)inSz, iv, (word32)ivSz, authTag, authTagSz,
9295 aad, aadSz);
9296 #ifdef WOLFSSL_ASYNC_CRYPT
9297 /* async decrypt not available here, so block till done */
9298 ret = wc_AsyncWait(ret, &pkcs7->decryptKey.aes->asyncDev,
9299 WC_ASYNC_FLAG_NONE);
9300 #endif
9301 break;
9302 #endif /* HAVE_AESCCM */
9303#endif /* !NO_AES */
9304#ifndef NO_DES3
9305 case DESb:
9306 ret = wc_Des_CbcDecrypt(pkcs7->decryptKey.des, out, in,
9307 (word32)inSz);
9308 break;
9309
9310 case DES3b:
9311 ret = wc_Des3_CbcDecrypt(pkcs7->decryptKey.des3, out, in,
9312 (word32)inSz);
9313 #ifdef WOLFSSL_ASYNC_CRYPT
9314 /* async decrypt not available here, so block till done */
9315 ret = wc_AsyncWait(ret,
9316 &pkcs7->decryptKey.des3->asyncDev, WC_ASYNC_FLAG_NONE);
9317 #endif
9318 break;
9319#endif /* !NO_DES3 */
9320 default:
9321 WOLFSSL_MSG("Unsupported content cipher type");
9322 return ALGO_ID_E;
9323 };
9324
9325#if defined(NO_AES) || (!defined(HAVE_AESGCM) && !defined(HAVE_AESCCM))
9326 (void)authTag;
9327 (void)authTagSz;
9328 (void)aad;
9329 (void)aadSz;
9330#endif
9331
9332 return ret;
9333}
9334
9335
9336/* clears up struct for algo used and free's memory */
9337static void wc_PKCS7_DecryptContentFree(wc_PKCS7* pkcs7, word32 encryptOID,
9338 void* heap)
9339{
9340 switch (encryptOID) {
9341#ifndef NO_AES
9342 #ifdef HAVE_AES_CBC
9343 #ifdef WOLFSSL_AES_128
9344 case AES128CBCb:
9345 #endif
9346 #ifdef WOLFSSL_AES_192
9347 case AES192CBCb:
9348 #endif
9349 #ifdef WOLFSSL_AES_256
9350 case AES256CBCb:
9351 #endif
9352 #endif /* HAVE_AES_CBC */
9353 #ifdef HAVE_AESGCM
9354 #ifdef WOLFSSL_AES_128
9355 case AES128GCMb:
9356 #endif
9357 #ifdef WOLFSSL_AES_192
9358 case AES192GCMb:
9359 #endif
9360 #ifdef WOLFSSL_AES_256
9361 case AES256GCMb:
9362 #endif
9363 #endif /* HAVE_AESGCM */
9364 #ifdef HAVE_AESCCM
9365 #ifdef WOLFSSL_AES_128
9366 case AES128CCMb:
9367 #endif
9368 #ifdef WOLFSSL_AES_192
9369 case AES192CCMb:
9370 #endif
9371 #ifdef WOLFSSL_AES_256
9372 case AES256CCMb:
9373 #endif
9374 #endif /* HAVE_AESCCM */
9375 if (pkcs7->decryptKey.aes != NULL) {
9376 wc_AesFree(pkcs7->decryptKey.aes);
9377 XFREE(pkcs7->decryptKey.aes, heap, DYNAMIC_TYPE_AES);
9378 pkcs7->decryptKey.aes = NULL;
9379 }
9380 break;
9381#endif /* !NO_AES */
9382#ifndef NO_DES3
9383 case DESb:
9384 if (pkcs7->decryptKey.des != NULL) {
9385 XFREE(pkcs7->decryptKey.des, heap, DYNAMIC_TYPE_PKCS7);
9386 pkcs7->decryptKey.des = NULL;
9387 }
9388 break;
9389 case DES3b:
9390 if (pkcs7->decryptKey.des3 != NULL) {
9391 wc_Des3Free(pkcs7->decryptKey.des3);
9392 XFREE(pkcs7->decryptKey.des3, heap, DYNAMIC_TYPE_PKCS7);
9393 pkcs7->decryptKey.des3 = NULL;
9394 }
9395 break;
9396#endif /* !NO_DES3 */
9397 default:
9398 WOLFSSL_MSG("Unsupported content cipher type");
9399 };
9400}
9401
9402
9403/* decrypts the content in one shot, doing init / decrypt / free
9404 * returns 0 on success
9405 */
9406static int wc_PKCS7_DecryptContent(wc_PKCS7* pkcs7, word32 encryptOID,
9407 const byte* key, word32 keySz, const byte* iv, int ivSz,
9408 const byte* aad, word32 aadSz, const byte* authTag, word32 authTagSz,
9409 const byte* in, int inSz, byte* out, int devId, void* heap)
9410{
9411 int ret;
9412
9413 if (pkcs7->decryptionCb != NULL) {
9414 /* unsafe casts needed for backward compatibility of
9415 * CallbackDecryptContent.
9416 */
9417 return pkcs7->decryptionCb(pkcs7, (int)encryptOID, (byte *)(wc_ptr_t)iv,
9418 ivSz, (byte *)(wc_ptr_t)aad, aadSz,
9419 (byte *)(wc_ptr_t)authTag, authTagSz,
9420 (byte *)(wc_ptr_t)in, inSz, out,
9421 pkcs7->decryptionCtx);
9422 }
9423
9424 ret = wc_PKCS7_DecryptContentInit(pkcs7, encryptOID, key, keySz, iv, ivSz,
9425 devId, heap);
9426
9427 if (ret == 0) {
9428 ret = wc_PKCS7_DecryptContentEx(pkcs7, encryptOID, iv, ivSz, aad,
9429 aadSz, authTag, authTagSz, in, inSz, out);
9430 }
9431
9432 wc_PKCS7_DecryptContentFree(pkcs7, encryptOID, heap);
9433
9434 return ret;
9435}
9436
9437
9438/* Generate random block, place in out, return 0 on success negative on error.
9439 * Used for generation of IV, nonce, etc */
9440static int wc_PKCS7_GenerateBlock(wc_PKCS7* pkcs7, WC_RNG* rng, byte* out,
9441 word32 outSz)
9442{
9443 int ret;
9444 WC_RNG* rnd = NULL;
9445
9446 if (out == NULL || outSz == 0)
9447 return BAD_FUNC_ARG;
9448
9449 /* input RNG is optional, init local one if input rng is NULL */
9450 if (rng == NULL) {
9451 rnd = (WC_RNG*)XMALLOC(sizeof(WC_RNG), pkcs7->heap, DYNAMIC_TYPE_RNG);
9452 if (rnd == NULL)
9453 return MEMORY_E;
9454
9455 ret = wc_InitRng_ex(rnd, pkcs7->heap, pkcs7->devId);
9456 if (ret != 0) {
9457 XFREE(rnd, pkcs7->heap, DYNAMIC_TYPE_RNG);
9458 return ret;
9459 }
9460
9461 } else {
9462 rnd = rng;
9463 }
9464
9465 ret = wc_RNG_GenerateBlock(rnd, out, outSz);
9466
9467 if (rng == NULL) {
9468 wc_FreeRng(rnd);
9469 XFREE(rnd, pkcs7->heap, DYNAMIC_TYPE_RNG);
9470 }
9471
9472 return ret;
9473}
9474
9475
9476/* Set default SignerIdentifier type to be used. Is either
9477 * IssuerAndSerialNumber or SubjectKeyIdentifier. Encoding defaults to using
9478 * IssuerAndSerialNumber unless set with this function or explicitly
9479 * overridden via options when adding RecipientInfo type.
9480 *
9481 * Using the type DEGENERATE_SID skips over signer information. In degenerate
9482 * cases there are no signers.
9483 *
9484 * pkcs7 - pointer to initialized PKCS7 structure
9485 * type - either CMS_ISSUER_AND_SERIAL_NUMBER, CMS_SKID or DEGENERATE_SID
9486 *
9487 * return 0 on success, negative upon error */
9488int wc_PKCS7_SetSignerIdentifierType(wc_PKCS7* pkcs7, int type)
9489{
9490 if (pkcs7 == NULL)
9491 return BAD_FUNC_ARG;
9492
9493 if (type != CMS_ISSUER_AND_SERIAL_NUMBER &&
9494 type != CMS_SKID &&
9495 type != DEGENERATE_SID) {
9496 return BAD_FUNC_ARG;
9497 }
9498
9499 pkcs7->sidType = type;
9500
9501 return 0;
9502}
9503
9504
9505/* Set custom contentType, currently supported with SignedData type
9506 *
9507 * pkcs7 - pointer to initialized PKCS7 structure
9508 * contentType - pointer to array with ASN.1 encoded OID value
9509 * sz - length of contentType array, octets
9510 *
9511 * return 0 on success, negative upon error */
9512int wc_PKCS7_SetContentType(wc_PKCS7* pkcs7, byte* contentType, word32 sz)
9513{
9514 if (pkcs7 == NULL || contentType == NULL || sz == 0)
9515 return BAD_FUNC_ARG;
9516
9517 if (sz > MAX_OID_SZ) {
9518 WOLFSSL_MSG("input array too large, bounded by MAX_OID_SZ");
9519 return BAD_FUNC_ARG;
9520 }
9521
9522 XMEMCPY(pkcs7->contentType, contentType, sz);
9523 pkcs7->contentTypeSz = sz;
9524
9525 return 0;
9526}
9527
9528
9529/* return size of padded data, padded to blockSz chunks, or negative on error */
9530int wc_PKCS7_GetPadSize(word32 inputSz, word32 blockSz)
9531{
9532 if (blockSz == 0)
9533 return BAD_FUNC_ARG;
9534
9535 return (int)(blockSz - (inputSz % blockSz));
9536}
9537
9538
9539/* pad input data to blockSz chunk, place in outSz. out must be big enough
9540 * for input + pad bytes. See wc_PKCS7_GetPadSize() helper. */
9541int wc_PKCS7_PadData(byte* in, word32 inSz, byte* out, word32 outSz,
9542 word32 blockSz)
9543{
9544 if (in == NULL || inSz == 0 ||
9545 out == NULL || outSz == 0 || blockSz == 0)
9546 return BAD_FUNC_ARG;
9547
9548 if (outSz < wc_PkcsPad(NULL, inSz, blockSz))
9549 return BAD_FUNC_ARG;
9550
9551 XMEMCPY(out, in, inSz);
9552
9553 return (int)wc_PkcsPad(out, inSz, blockSz);
9554}
9555
9556
9557/* Encode and add CMS EnvelopedData ORI (OtherRecipientInfo) RecipientInfo
9558 * to CMS/PKCS#7 EnvelopedData structure.
9559 *
9560 * Return 0 on success, negative upon error */
9561int wc_PKCS7_AddRecipient_ORI(wc_PKCS7* pkcs7, CallbackOriEncrypt oriEncryptCb,
9562 int options)
9563{
9564 int oriTypeLenSz, blockKeySz, ret;
9565 word32 idx, recipSeqSz;
9566
9567 Pkcs7EncodedRecip* recip = NULL;
9568 Pkcs7EncodedRecip* lastRecip = NULL;
9569
9570 byte recipSeq[MAX_SEQ_SZ];
9571 byte oriTypeLen[MAX_LENGTH_SZ];
9572
9573 byte oriType[MAX_ORI_TYPE_SZ];
9574 byte oriValue[MAX_ORI_VALUE_SZ];
9575 word32 oriTypeSz = MAX_ORI_TYPE_SZ;
9576 word32 oriValueSz = MAX_ORI_VALUE_SZ;
9577
9578 if (pkcs7 == NULL || oriEncryptCb == NULL) {
9579 return BAD_FUNC_ARG;
9580 }
9581
9582 /* allocate memory for RecipientInfo, KEK, encrypted key */
9583 recip = (Pkcs7EncodedRecip*)XMALLOC(sizeof(Pkcs7EncodedRecip),
9584 pkcs7->heap, DYNAMIC_TYPE_PKCS7);
9585 if (recip == NULL)
9586 return MEMORY_E;
9587 XMEMSET(recip, 0, sizeof(Pkcs7EncodedRecip));
9588
9589 /* get key size for content-encryption key based on algorithm */
9590 blockKeySz = wc_PKCS7_GetOIDKeySize(pkcs7->encryptOID);
9591 if (blockKeySz < 0) {
9592 XFREE(recip, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
9593 return blockKeySz;
9594 }
9595
9596 /* generate random content encryption key, if needed */
9597 ret = PKCS7_GenerateContentEncryptionKey(pkcs7, (word32)blockKeySz);
9598 if (ret < 0) {
9599 XFREE(recip, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
9600 return ret;
9601 }
9602
9603 /* call user callback to encrypt CEK and get oriType and oriValue
9604 values back */
9605 ret = oriEncryptCb(pkcs7, pkcs7->cek, pkcs7->cekSz, oriType, &oriTypeSz,
9606 oriValue, &oriValueSz, pkcs7->oriEncryptCtx);
9607 if (ret != 0) {
9608 XFREE(recip, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
9609 return ret;
9610 }
9611
9612 oriTypeLenSz = (int)SetLength(oriTypeSz, oriTypeLen);
9613
9614 recipSeqSz = SetImplicit(ASN_SEQUENCE, 4, 1 + (word32)oriTypeLenSz +
9615 oriTypeSz + oriValueSz, recipSeq, 0);
9616
9617 idx = 0;
9618 XMEMCPY(recip->recip + idx, recipSeq, recipSeqSz);
9619 idx += recipSeqSz;
9620 /* oriType */
9621 recip->recip[idx] = ASN_OBJECT_ID;
9622 idx += 1;
9623 XMEMCPY(recip->recip + idx, oriTypeLen, (word32)oriTypeLenSz);
9624 idx += (word32)oriTypeLenSz;
9625 XMEMCPY(recip->recip + idx, oriType, oriTypeSz);
9626 idx += oriTypeSz;
9627 /* oriValue, input MUST already be ASN.1 encoded */
9628 XMEMCPY(recip->recip + idx, oriValue, oriValueSz);
9629 idx += oriValueSz;
9630
9631 /* store recipient size */
9632 recip->recipSz = idx;
9633 recip->recipType = PKCS7_ORI;
9634 recip->recipVersion = 4;
9635
9636 /* add recipient to recip list */
9637 if (pkcs7->recipList == NULL) {
9638 pkcs7->recipList = recip;
9639 } else {
9640 lastRecip = pkcs7->recipList;
9641 while (lastRecip->next != NULL) {
9642 lastRecip = lastRecip->next;
9643 }
9644 lastRecip->next = recip;
9645 }
9646
9647 (void)options;
9648
9649 return (int)idx;
9650}
9651
9652#if !defined(NO_PWDBASED) && !defined(NO_SHA)
9653
9654
9655static int wc_PKCS7_GenerateKEK_PWRI(wc_PKCS7* pkcs7, byte* passwd, word32 pLen,
9656 byte* salt, word32 saltSz, int kdfOID,
9657 int prfOID, int iterations, byte* out,
9658 word32 outSz)
9659{
9660 int ret;
9661
9662 if (pkcs7 == NULL || passwd == NULL || salt == NULL || out == NULL)
9663 return BAD_FUNC_ARG;
9664
9665 switch (kdfOID) {
9666
9667 case PBKDF2_OID:
9668
9669 ret = wc_PBKDF2(out, passwd, (int)pLen, salt, (int)saltSz,
9670 iterations, (int)outSz, prfOID);
9671 if (ret != 0) {
9672 return ret;
9673 }
9674
9675 break;
9676
9677 default:
9678 WOLFSSL_MSG("Unsupported KDF OID");
9679 return PKCS7_OID_E;
9680 }
9681
9682 return 0;
9683}
9684
9685
9686/* RFC3211 (Section 2.3.1) key wrap algorithm (id-alg-PWRI-KEK).
9687 *
9688 * Returns output size on success, negative upon error */
9689static int wc_PKCS7_PwriKek_KeyWrap(wc_PKCS7* pkcs7, const byte* kek,
9690 word32 kekSz, const byte* cek, word32 cekSz,
9691 byte* out, word32 *outSz, const byte* iv, word32 ivSz, int algID)
9692{
9693 WC_RNG rng;
9694 int blockSz, outLen, ret;
9695 word32 padSz;
9696 byte* lastBlock;
9697
9698 if (kek == NULL || cek == NULL || iv == NULL || outSz == NULL)
9699 return BAD_FUNC_ARG;
9700
9701 /* get encryption algorithm block size */
9702 blockSz = wc_PKCS7_GetOIDBlockSize(algID);
9703 if (blockSz <= 0) {
9704 if (blockSz < 0)
9705 return blockSz;
9706 else
9707 return ALGO_ID_E;
9708 }
9709
9710 /* get pad bytes needed to block boundary */
9711 padSz = (word32)blockSz - ((4 + cekSz) % (word32)blockSz);
9712 outLen = (int)(4 + cekSz + padSz);
9713
9714 /* must be at least two blocks long */
9715 if (outLen < 2 * blockSz)
9716 padSz += (word32)blockSz;
9717
9718 /* if user set out to NULL, give back required length */
9719 if (out == NULL) {
9720 *outSz = (word32)outLen;
9721 return WC_NO_ERR_TRACE(LENGTH_ONLY_E);
9722 }
9723
9724 /* verify output buffer is large enough */
9725 if (*outSz < (word32)outLen)
9726 return BUFFER_E;
9727
9728 out[0] = (byte)cekSz;
9729 out[1] = (byte)~cek[0];
9730 out[2] = (byte)~cek[1];
9731 out[3] = (byte)~cek[2];
9732 XMEMCPY(out + 4, cek, cekSz);
9733
9734 /* random padding of size padSz */
9735 ret = wc_InitRng_ex(&rng, pkcs7->heap, pkcs7->devId);
9736 if (ret != 0)
9737 return ret;
9738
9739 ret = wc_RNG_GenerateBlock(&rng, out + 4 + cekSz, padSz);
9740
9741 if (ret == 0) {
9742 /* encrypt, normal */
9743 ret = wc_PKCS7_EncryptContent(pkcs7, algID, kek, (int)kekSz,
9744 iv, (int)ivSz, NULL, 0, NULL, 0, out,
9745 outLen, out);
9746 }
9747
9748 if (ret == 0) {
9749 /* encrypt again, using last ciphertext block as IV */
9750 lastBlock = out + (((outLen / blockSz) - 1) * blockSz);
9751 ret = wc_PKCS7_EncryptContent(pkcs7, algID, kek, (int)kekSz,
9752 lastBlock, blockSz, NULL, 0, NULL, 0, out,
9753 outLen, out);
9754 }
9755
9756 if (ret == 0) {
9757 *outSz = (word32)outLen;
9758 } else {
9759 outLen = ret;
9760 }
9761
9762 wc_FreeRng(&rng);
9763
9764 return outLen;
9765}
9766
9767
9768/* RFC3211 (Section 2.3.2) key unwrap algorithm (id-alg-PWRI-KEK).
9769 *
9770 * Returns cek size on success, negative upon error */
9771static int wc_PKCS7_PwriKek_KeyUnWrap(wc_PKCS7* pkcs7, const byte* kek,
9772 word32 kekSz, const byte* in, word32 inSz,
9773 byte* out, word32 outSz, const byte* iv,
9774 word32 ivSz, word32 algID)
9775{
9776 int blockSz, cekLen, ret;
9777 const byte* tmpIv = NULL;
9778 const byte* lastBlock = NULL;
9779 byte* outTmp = NULL;
9780 byte fail = 0;
9781
9782 if (pkcs7 == NULL || kek == NULL || in == NULL ||
9783 out == NULL || iv == NULL) {
9784 return BAD_FUNC_ARG;
9785 }
9786
9787 outTmp = (byte*)XMALLOC(inSz, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
9788 if (outTmp == NULL)
9789 return MEMORY_E;
9790
9791 /* get encryption algorithm block size */
9792 blockSz = wc_PKCS7_GetOIDBlockSize((int)algID);
9793 if (blockSz <= 0) {
9794 XFREE(outTmp, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
9795 if (blockSz < 0)
9796 return blockSz;
9797 else
9798 return ALGO_ID_E;
9799 }
9800
9801 /* input needs to be blockSz multiple and at least 2 * blockSz */
9802 if (((inSz % (word32)blockSz) != 0) || (inSz < (2 * (word32)blockSz))) {
9803 WOLFSSL_MSG("PWRI-KEK unwrap input must of block size and >= 2 "
9804 "times block size");
9805 XFREE(outTmp, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
9806 return BAD_FUNC_ARG;
9807 }
9808
9809 /* use block out[n-1] as IV to decrypt block out[n] */
9810 lastBlock = in + inSz - blockSz;
9811 tmpIv = lastBlock - blockSz;
9812
9813 /* decrypt last block */
9814 ret = wc_PKCS7_DecryptContent(pkcs7, algID, kek, kekSz, tmpIv,
9815 blockSz, NULL, 0, NULL, 0, lastBlock, blockSz,
9816 outTmp + inSz - blockSz, pkcs7->devId, pkcs7->heap);
9817
9818 if (ret == 0) {
9819 /* using last decrypted block as IV, decrypt [0 ... n-1] blocks */
9820 lastBlock = outTmp + inSz - blockSz;
9821 ret = wc_PKCS7_DecryptContent(pkcs7, algID, kek, kekSz,
9822 lastBlock, blockSz, NULL, 0, NULL, 0, in,
9823 (int)inSz - blockSz, outTmp, pkcs7->devId, pkcs7->heap);
9824 }
9825
9826 if (ret == 0) {
9827 /* decrypt using original kek and iv */
9828 ret = wc_PKCS7_DecryptContent(pkcs7, algID, kek, kekSz,
9829 iv, (int)ivSz, NULL, 0, NULL, 0, outTmp, (int)inSz,
9830 outTmp, pkcs7->devId, pkcs7->heap);
9831 }
9832
9833 if (ret != 0) {
9834 ForceZero(outTmp, inSz);
9835 XFREE(outTmp, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
9836 return ret;
9837 }
9838
9839 cekLen = outTmp[0];
9840
9841 /* verify length */
9842 fail |= ctMaskGT(cekLen, (int)inSz - 4);
9843 /* verify check bytes */
9844 fail |= ctMaskNotEq((int)(outTmp[1] ^ outTmp[4]), 0xFF);
9845 fail |= ctMaskNotEq((int)(outTmp[2] ^ outTmp[5]), 0xFF);
9846 fail |= ctMaskNotEq((int)(outTmp[3] ^ outTmp[6]), 0xFF);
9847 /* verify length */
9848 fail |= ctMaskGT(cekLen, (int)outSz);
9849
9850 if (fail) {
9851 ForceZero(outTmp, inSz);
9852 XFREE(outTmp, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
9853 return BAD_FUNC_ARG;
9854 }
9855
9856 XMEMCPY(out, outTmp + 4, outTmp[0]);
9857 ForceZero(outTmp, inSz);
9858 XFREE(outTmp, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
9859
9860 return cekLen;
9861}
9862
9863
9864/* Encode and add CMS EnvelopedData PWRI (PasswordRecipientInfo) RecipientInfo
9865 * to CMS/PKCS#7 EnvelopedData structure.
9866 *
9867 * Return 0 on success, negative upon error */
9868int wc_PKCS7_AddRecipient_PWRI(wc_PKCS7* pkcs7, byte* passwd, word32 pLen,
9869 byte* salt, word32 saltSz, int kdfOID,
9870 int hashOID, int iterations, int kekEncryptOID,
9871 int options)
9872{
9873 Pkcs7EncodedRecip* recip = NULL;
9874 Pkcs7EncodedRecip* lastRecip = NULL;
9875
9876 /* PasswordRecipientInfo */
9877 byte recipSeq[MAX_SEQ_SZ];
9878 byte ver[MAX_VERSION_SZ];
9879 word32 recipSeqSz, verSz;
9880
9881 /* KeyDerivationAlgorithmIdentifier */
9882 byte kdfAlgoIdSeq[MAX_SEQ_SZ];
9883 byte kdfAlgoId[MAX_OID_SZ];
9884 byte kdfParamsSeq[MAX_SEQ_SZ]; /* PBKDF2-params */
9885 byte kdfSaltOctetStr[MAX_OCTET_STR_SZ]; /* salt OCTET STRING */
9886 byte kdfIterations[MAX_VERSION_SZ];
9887 word32 kdfAlgoIdSeqSz, kdfAlgoIdSz;
9888 word32 kdfParamsSeqSz, kdfSaltOctetStrSz, kdfIterationsSz;
9889 /* OPTIONAL: keyLength, not supported yet */
9890 /* OPTIONAL: prf AlgorithmIdentifier, not supported yet */
9891
9892 /* KeyEncryptionAlgorithmIdentifier */
9893 byte keyEncAlgoIdSeq[MAX_SEQ_SZ];
9894 byte keyEncAlgoId[MAX_OID_SZ]; /* id-alg-PWRI-KEK */
9895 byte pwriEncAlgoId[MAX_ALGO_SZ];
9896 byte ivOctetString[MAX_OCTET_STR_SZ];
9897 word32 keyEncAlgoIdSeqSz, keyEncAlgoIdSz;
9898 word32 pwriEncAlgoIdSz, ivOctetStringSz;
9899
9900 /* EncryptedKey */
9901 byte encKeyOctetStr[MAX_OCTET_STR_SZ];
9902 word32 encKeyOctetStrSz;
9903
9904 byte tmpIv[MAX_CONTENT_IV_SIZE];
9905 byte* encryptedKey = NULL;
9906 byte* kek = NULL;
9907
9908 int cekKeySz = 0, kekKeySz = 0, kekBlockSz = 0, ret = 0;
9909 int encryptOID;
9910 word32 idx, totalSz = 0, encryptedKeySz;
9911
9912 if (pkcs7 == NULL || passwd == NULL || pLen == 0 ||
9913 salt == NULL || saltSz == 0) {
9914 return BAD_FUNC_ARG;
9915 }
9916
9917 /* allow user to use different KEK encryption algorithm than used for
9918 * main content encryption algorithm, if passed in */
9919 if (kekEncryptOID != 0) {
9920 encryptOID = kekEncryptOID;
9921 } else {
9922 encryptOID = pkcs7->encryptOID;
9923 }
9924
9925 /* get content-encryption key size, based on algorithm */
9926 cekKeySz = wc_PKCS7_GetOIDKeySize(pkcs7->encryptOID);
9927 if (cekKeySz < 0)
9928 return cekKeySz;
9929
9930 /* get KEK encryption key size, based on algorithm */
9931 if (encryptOID != pkcs7->encryptOID) {
9932 kekKeySz = wc_PKCS7_GetOIDKeySize(encryptOID);
9933 } else {
9934 kekKeySz = cekKeySz;
9935 }
9936
9937 /* get KEK encryption block size */
9938 kekBlockSz = wc_PKCS7_GetOIDBlockSize(encryptOID);
9939 if (kekBlockSz < 0)
9940 return kekBlockSz;
9941
9942 /* generate random CEK */
9943 ret = PKCS7_GenerateContentEncryptionKey(pkcs7, (word32)cekKeySz);
9944 if (ret < 0)
9945 return ret;
9946
9947 /* generate random IV */
9948 ret = wc_PKCS7_GenerateBlock(pkcs7, NULL, tmpIv, (word32)kekBlockSz);
9949 if (ret != 0)
9950 return ret;
9951
9952 /* allocate memory for RecipientInfo, KEK, encrypted key */
9953 recip = (Pkcs7EncodedRecip*)XMALLOC(sizeof(Pkcs7EncodedRecip),
9954 pkcs7->heap, DYNAMIC_TYPE_PKCS7);
9955 if (recip == NULL)
9956 return MEMORY_E;
9957
9958 kek = (byte*)XMALLOC((word32)kekKeySz, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
9959 if (kek == NULL) {
9960 XFREE(recip, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
9961 return MEMORY_E;
9962 }
9963
9964 encryptedKey = (byte*)XMALLOC(MAX_ENCRYPTED_KEY_SZ,
9965 pkcs7->heap, DYNAMIC_TYPE_PKCS7);
9966 if (encryptedKey == NULL) {
9967 XFREE(recip, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
9968 XFREE(kek, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
9969 return MEMORY_E;
9970 }
9971
9972 encryptedKeySz = MAX_ENCRYPTED_KEY_SZ;
9973 XMEMSET(recip, 0, sizeof(Pkcs7EncodedRecip));
9974 XMEMSET(kek, 0, (word32)kekKeySz);
9975 XMEMSET(encryptedKey, 0, encryptedKeySz);
9976
9977 /* generate KEK: expand password into KEK */
9978 ret = wc_PKCS7_GenerateKEK_PWRI(pkcs7, passwd, pLen, salt, saltSz,
9979 kdfOID, hashOID, iterations, kek,
9980 (word32)kekKeySz);
9981 if (ret < 0) {
9982 XFREE(recip, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
9983 ForceZero(kek, (word32)kekKeySz);
9984 XFREE(kek, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
9985 XFREE(encryptedKey, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
9986 return ret;
9987 }
9988
9989 /* generate encrypted key: encrypt CEK with KEK */
9990 ret = wc_PKCS7_PwriKek_KeyWrap(pkcs7, kek, (word32)kekKeySz, pkcs7->cek,
9991 pkcs7->cekSz, encryptedKey, &encryptedKeySz,
9992 tmpIv, (word32)kekBlockSz, encryptOID);
9993 if (ret < 0) {
9994 XFREE(recip, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
9995 ForceZero(kek, (word32)kekKeySz);
9996 XFREE(kek, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
9997 XFREE(encryptedKey, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
9998 return ret;
9999 }
10000 encryptedKeySz = (word32)ret;
10001
10002 /* put together encrypted key OCTET STRING */
10003 encKeyOctetStrSz = SetOctetString(encryptedKeySz, encKeyOctetStr);
10004 totalSz += (encKeyOctetStrSz + encryptedKeySz);
10005
10006 /* put together IV OCTET STRING */
10007 ivOctetStringSz = SetOctetString((word32)kekBlockSz, ivOctetString);
10008 totalSz += (ivOctetStringSz + (word32)kekBlockSz);
10009
10010 /* set PWRIAlgorithms AlgorithmIdentifier, adding (ivOctetStringSz +
10011 blockKeySz) for IV OCTET STRING */
10012 pwriEncAlgoIdSz = SetAlgoID(encryptOID, pwriEncAlgoId,
10013 oidBlkType, (int)ivOctetStringSz + kekBlockSz);
10014 totalSz += pwriEncAlgoIdSz;
10015
10016 /* set KeyEncryptionAlgorithms OID */
10017 ret = wc_SetContentType(PWRI_KEK_WRAP, keyEncAlgoId, sizeof(keyEncAlgoId));
10018 if (ret <= 0) {
10019 XFREE(recip, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
10020 ForceZero(kek, (word32)kekKeySz);
10021 XFREE(kek, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
10022 XFREE(encryptedKey, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
10023 return ret;
10024 }
10025 keyEncAlgoIdSz = (word32)ret;
10026 totalSz += keyEncAlgoIdSz;
10027
10028 /* KeyEncryptionAlgorithm SEQ */
10029 keyEncAlgoIdSeqSz = SetSequence(keyEncAlgoIdSz + pwriEncAlgoIdSz +
10030 ivOctetStringSz + (word32)kekBlockSz,
10031 keyEncAlgoIdSeq);
10032 totalSz += keyEncAlgoIdSeqSz;
10033
10034 /* set KDF salt */
10035 kdfSaltOctetStrSz = SetOctetString(saltSz, kdfSaltOctetStr);
10036 totalSz += (kdfSaltOctetStrSz + saltSz);
10037
10038 /* set KDF iteration count */
10039 kdfIterationsSz = (word32)SetMyVersion((word32)iterations, kdfIterations,
10040 0);
10041 totalSz += kdfIterationsSz;
10042
10043 /* set KDF params SEQ */
10044 kdfParamsSeqSz = SetSequence(kdfSaltOctetStrSz + saltSz + kdfIterationsSz,
10045 kdfParamsSeq);
10046 totalSz += kdfParamsSeqSz;
10047
10048 /* set KDF algo OID */
10049 ret = wc_SetContentType(kdfOID, kdfAlgoId, sizeof(kdfAlgoId));
10050 if (ret <= 0) {
10051 XFREE(recip, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
10052 ForceZero(kek, (word32)kekKeySz);
10053 XFREE(kek, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
10054 XFREE(encryptedKey, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
10055 return ret;
10056 }
10057 kdfAlgoIdSz = (word32)ret;
10058 totalSz += kdfAlgoIdSz;
10059
10060 /* set KeyDerivationAlgorithmIdentifier EXPLICIT [0] SEQ */
10061 kdfAlgoIdSeqSz = SetExplicit(0, kdfAlgoIdSz + kdfParamsSeqSz +
10062 kdfSaltOctetStrSz + saltSz + kdfIterationsSz,
10063 kdfAlgoIdSeq, 0);
10064 totalSz += kdfAlgoIdSeqSz;
10065
10066 /* set PasswordRecipientInfo CMSVersion, MUST be 0 */
10067 verSz = (word32)SetMyVersion(0, ver, 0);
10068 totalSz += verSz;
10069 recip->recipVersion = 0;
10070
10071 /* set PasswordRecipientInfo SEQ */
10072 recipSeqSz = SetImplicit(ASN_SEQUENCE, 3, totalSz, recipSeq, 0);
10073 totalSz += recipSeqSz;
10074
10075 if (totalSz > MAX_RECIP_SZ) {
10076 WOLFSSL_MSG("CMS Recipient output buffer too small");
10077 XFREE(recip, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
10078 ForceZero(kek, (word32)kekKeySz);
10079 XFREE(kek, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
10080 XFREE(encryptedKey, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
10081 return BUFFER_E;
10082 }
10083
10084 idx = 0;
10085 XMEMCPY(recip->recip + idx, recipSeq, recipSeqSz);
10086 idx += recipSeqSz;
10087 XMEMCPY(recip->recip + idx, ver, verSz);
10088 idx += verSz;
10089 XMEMCPY(recip->recip + idx, kdfAlgoIdSeq, kdfAlgoIdSeqSz);
10090 idx += kdfAlgoIdSeqSz;
10091 XMEMCPY(recip->recip + idx, kdfAlgoId, kdfAlgoIdSz);
10092 idx += kdfAlgoIdSz;
10093 XMEMCPY(recip->recip + idx, kdfParamsSeq, kdfParamsSeqSz);
10094 idx += kdfParamsSeqSz;
10095 XMEMCPY(recip->recip + idx, kdfSaltOctetStr, kdfSaltOctetStrSz);
10096 idx += kdfSaltOctetStrSz;
10097 XMEMCPY(recip->recip + idx, salt, saltSz);
10098 idx += saltSz;
10099 XMEMCPY(recip->recip + idx, kdfIterations, kdfIterationsSz);
10100 idx += kdfIterationsSz;
10101 XMEMCPY(recip->recip + idx, keyEncAlgoIdSeq, keyEncAlgoIdSeqSz);
10102 idx += keyEncAlgoIdSeqSz;
10103 XMEMCPY(recip->recip + idx, keyEncAlgoId, keyEncAlgoIdSz);
10104 idx += keyEncAlgoIdSz;
10105 XMEMCPY(recip->recip + idx, pwriEncAlgoId, pwriEncAlgoIdSz);
10106 idx += pwriEncAlgoIdSz;
10107 XMEMCPY(recip->recip + idx, ivOctetString, ivOctetStringSz);
10108 idx += ivOctetStringSz;
10109 XMEMCPY(recip->recip + idx, tmpIv, (word32)kekBlockSz);
10110 idx += (word32)kekBlockSz;
10111 XMEMCPY(recip->recip + idx, encKeyOctetStr, encKeyOctetStrSz);
10112 idx += encKeyOctetStrSz;
10113 XMEMCPY(recip->recip + idx, encryptedKey, encryptedKeySz);
10114 idx += encryptedKeySz;
10115
10116 ForceZero(kek, (word32)kekKeySz);
10117 ForceZero(encryptedKey, encryptedKeySz);
10118 XFREE(kek, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
10119 XFREE(encryptedKey, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
10120
10121 /* store recipient size */
10122 recip->recipSz = idx;
10123 recip->recipType = PKCS7_PWRI;
10124
10125 /* add recipient to recip list */
10126 if (pkcs7->recipList == NULL) {
10127 pkcs7->recipList = recip;
10128 } else {
10129 lastRecip = pkcs7->recipList;
10130 while (lastRecip->next != NULL) {
10131 lastRecip = lastRecip->next;
10132 }
10133 lastRecip->next = recip;
10134 }
10135
10136 (void)options;
10137
10138 return (int)idx;
10139}
10140
10141/* Import password and KDF settings into a PKCS7 structure. Used for setting
10142 * the password info for decryption a EnvelopedData PWRI RecipientInfo.
10143 *
10144 * Returns 0 on success, negative upon error */
10145int wc_PKCS7_SetPassword(wc_PKCS7* pkcs7, byte* passwd, word32 pLen)
10146{
10147 if (pkcs7 == NULL || passwd == NULL || pLen == 0)
10148 return BAD_FUNC_ARG;
10149
10150 pkcs7->pass = passwd;
10151 pkcs7->passSz = pLen;
10152
10153 return 0;
10154}
10155
10156#endif /* NO_PWDBASED */
10157
10158
10159/* Encode and add CMS EnvelopedData KEKRI (KEKRecipientInfo) RecipientInfo
10160 * to CMS/PKCS#7 EnvelopedData structure.
10161 *
10162 * pkcs7 - pointer to initialized PKCS7 structure
10163 * keyWrapOID - OID sum of key wrap algorithm identifier
10164 * kek - key encryption key
10165 * kekSz - size of kek, bytes
10166 * keyID - key-encryption key identifier, pre-distributed to endpoints
10167 * keyIDSz - size of keyID, bytes
10168 * timePtr - pointer to "time_t", which is typically "long" (OPTIONAL)
10169 * otherOID - ASN.1 encoded OID of other attribute (OPTIONAL)
10170 * otherOIDSz - size of otherOID, bytes (OPTIONAL)
10171 * other - other attribute (OPTIONAL)
10172 * otherSz - size of other (OPTIONAL)
10173 *
10174 * Returns 0 on success, negative upon error */
10175int wc_PKCS7_AddRecipient_KEKRI(wc_PKCS7* pkcs7, int keyWrapOID, byte* kek,
10176 word32 kekSz, byte* keyId, word32 keyIdSz,
10177 void* timePtr, byte* otherOID,
10178 word32 otherOIDSz, byte* other, word32 otherSz,
10179 int options)
10180{
10181 Pkcs7EncodedRecip* recip = NULL;
10182 Pkcs7EncodedRecip* lastRecip = NULL;
10183
10184 byte recipSeq[MAX_SEQ_SZ];
10185 byte ver[MAX_VERSION_SZ];
10186 byte kekIdSeq[MAX_SEQ_SZ];
10187 byte kekIdOctetStr[MAX_OCTET_STR_SZ];
10188 byte genTime[ASN_GENERALIZED_TIME_SIZE];
10189 byte otherAttSeq[MAX_SEQ_SZ];
10190 byte encAlgoId[MAX_ALGO_SZ];
10191 byte encKeyOctetStr[MAX_OCTET_STR_SZ];
10192 WC_DECLARE_VAR(encryptedKey, byte, MAX_ENCRYPTED_KEY_SZ, 0);
10193
10194 int blockKeySz = 0, ret = 0, direction;
10195 word32 idx = 0;
10196 word32 totalSz = 0;
10197 word32 recipSeqSz = 0, verSz = 0;
10198 word32 kekIdSeqSz = 0, kekIdOctetStrSz = 0;
10199 word32 otherAttSeqSz = 0, encAlgoIdSz = 0, encKeyOctetStrSz = 0;
10200 int encryptedKeySz;
10201
10202 int timeSz = 0;
10203#ifndef NO_ASN_TIME
10204 time_t* tm = NULL;
10205#endif
10206
10207 if (pkcs7 == NULL || kek == NULL || keyId == NULL)
10208 return BAD_FUNC_ARG;
10209
10210 recip = (Pkcs7EncodedRecip*)XMALLOC(sizeof(Pkcs7EncodedRecip), pkcs7->heap,
10211 DYNAMIC_TYPE_PKCS7);
10212 if (recip == NULL)
10213 return MEMORY_E;
10214
10215 XMEMSET(recip, 0, sizeof(Pkcs7EncodedRecip));
10216
10217 /* get key size for content-encryption key based on algorithm */
10218 blockKeySz = wc_PKCS7_GetOIDKeySize(pkcs7->encryptOID);
10219 if (blockKeySz < 0) {
10220 XFREE(recip, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
10221 return blockKeySz;
10222 }
10223
10224 /* generate random content encryption key, if needed */
10225 ret = PKCS7_GenerateContentEncryptionKey(pkcs7, (word32)blockKeySz);
10226 if (ret < 0) {
10227 XFREE(recip, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
10228 return ret;
10229 }
10230
10231 /* EncryptedKey */
10232#ifdef WOLFSSL_SMALL_STACK
10233 encryptedKey = (byte*)XMALLOC(MAX_ENCRYPTED_KEY_SZ, pkcs7->heap,
10234 DYNAMIC_TYPE_PKCS7);
10235 if (encryptedKey == NULL) {
10236 XFREE(recip, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
10237 return MEMORY_E;
10238 }
10239#endif
10240 encryptedKeySz = MAX_ENCRYPTED_KEY_SZ;
10241 XMEMSET(encryptedKey, 0, (word32)encryptedKeySz);
10242
10243 #ifndef NO_AES
10244 direction = AES_ENCRYPTION;
10245 #else
10246 direction = DES_ENCRYPTION;
10247 #endif
10248
10249 encryptedKeySz = wc_PKCS7_KeyWrap(pkcs7, pkcs7->cek, pkcs7->cekSz, kek,
10250 kekSz, encryptedKey, (word32)encryptedKeySz, keyWrapOID, direction);
10251 if (encryptedKeySz < 0) {
10252 WC_FREE_VAR_EX(encryptedKey, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
10253 XFREE(recip, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
10254 return encryptedKeySz;
10255 }
10256 /* handle a zero size encKey case as WC_KEY_SIZE_E */
10257 if (encryptedKeySz == 0 || encryptedKeySz > MAX_ENCRYPTED_KEY_SZ) {
10258 WC_FREE_VAR_EX(encryptedKey, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
10259 XFREE(recip, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
10260 return WC_KEY_SIZE_E;
10261 }
10262
10263 encKeyOctetStrSz = SetOctetString((word32)encryptedKeySz, encKeyOctetStr);
10264 totalSz += (encKeyOctetStrSz + (word32)encryptedKeySz);
10265
10266 /* KeyEncryptionAlgorithmIdentifier */
10267 encAlgoIdSz = SetAlgoID(keyWrapOID, encAlgoId, oidKeyWrapType, 0);
10268 totalSz += encAlgoIdSz;
10269
10270 /* KEKIdentifier: keyIdentifier */
10271 kekIdOctetStrSz = SetOctetString(keyIdSz, kekIdOctetStr);
10272 totalSz += (kekIdOctetStrSz + keyIdSz);
10273
10274 /* KEKIdentifier: GeneralizedTime (OPTIONAL) */
10275#ifndef NO_ASN_TIME
10276 if (timePtr != NULL) {
10277 tm = (time_t*)timePtr;
10278 timeSz = GetAsnTimeString(tm, genTime, sizeof(genTime));
10279 if (timeSz < 0) {
10280 XFREE(recip, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
10281 WC_FREE_VAR_EX(encryptedKey, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
10282 return timeSz;
10283 }
10284 totalSz += (word32)timeSz;
10285 }
10286#endif
10287
10288 /* KEKIdentifier: OtherKeyAttribute SEQ (OPTIONAL) */
10289 if (other != NULL && otherSz > 0) {
10290 otherAttSeqSz = SetSequence(otherOIDSz + otherSz, otherAttSeq);
10291 totalSz += otherAttSeqSz + otherOIDSz + otherSz;
10292 }
10293
10294 /* KEKIdentifier SEQ */
10295 kekIdSeqSz = SetSequence(kekIdOctetStrSz + keyIdSz + (word32)timeSz +
10296 otherAttSeqSz + otherOIDSz + otherSz, kekIdSeq);
10297 totalSz += kekIdSeqSz;
10298
10299 /* version */
10300 verSz = (word32)SetMyVersion(4, ver, 0);
10301 totalSz += verSz;
10302 recip->recipVersion = 4;
10303
10304 /* KEKRecipientInfo SEQ */
10305 recipSeqSz = SetImplicit(ASN_SEQUENCE, 2, totalSz, recipSeq, 0);
10306 totalSz += recipSeqSz;
10307
10308 if (totalSz > MAX_RECIP_SZ) {
10309 WOLFSSL_MSG("CMS Recipient output buffer too small");
10310 XFREE(recip, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
10311 WC_FREE_VAR_EX(encryptedKey, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
10312 return BUFFER_E;
10313 }
10314
10315 XMEMCPY(recip->recip + idx, recipSeq, recipSeqSz);
10316 idx += recipSeqSz;
10317 XMEMCPY(recip->recip + idx, ver, verSz);
10318 idx += verSz;
10319 XMEMCPY(recip->recip + idx, kekIdSeq, kekIdSeqSz);
10320 idx += kekIdSeqSz;
10321 XMEMCPY(recip->recip + idx, kekIdOctetStr, kekIdOctetStrSz);
10322 idx += kekIdOctetStrSz;
10323 XMEMCPY(recip->recip + idx, keyId, keyIdSz);
10324 idx += keyIdSz;
10325 if (timePtr != NULL) {
10326 XMEMCPY(recip->recip + idx, genTime, (word32)timeSz);
10327 idx += (word32)timeSz;
10328 }
10329 if (other != NULL && otherSz > 0) {
10330 XMEMCPY(recip->recip + idx, otherAttSeq, otherAttSeqSz);
10331 idx += otherAttSeqSz;
10332 XMEMCPY(recip->recip + idx, otherOID, otherOIDSz);
10333 idx += otherOIDSz;
10334 XMEMCPY(recip->recip + idx, other, otherSz);
10335 idx += otherSz;
10336 }
10337 XMEMCPY(recip->recip + idx, encAlgoId, encAlgoIdSz);
10338 idx += encAlgoIdSz;
10339 XMEMCPY(recip->recip + idx, encKeyOctetStr, encKeyOctetStrSz);
10340 idx += encKeyOctetStrSz;
10341 XMEMCPY(recip->recip + idx, encryptedKey, (word32)encryptedKeySz);
10342 idx += (word32)encryptedKeySz;
10343
10344 WC_FREE_VAR_EX(encryptedKey, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
10345
10346 /* store recipient size */
10347 recip->recipSz = idx;
10348 recip->recipType = PKCS7_KEKRI;
10349
10350 /* add recipient to recip list */
10351 if (pkcs7->recipList == NULL) {
10352 pkcs7->recipList = recip;
10353 } else {
10354 lastRecip = pkcs7->recipList;
10355 while(lastRecip->next != NULL) {
10356 lastRecip = lastRecip->next;
10357 }
10358 lastRecip->next = recip;
10359 }
10360
10361 (void)options;
10362
10363 return (int)idx;
10364}
10365
10366
10367static int wc_PKCS7_GetCMSVersion(wc_PKCS7* pkcs7, int cmsContentType)
10368{
10369 int version = -1;
10370
10371 if (pkcs7 == NULL)
10372 return BAD_FUNC_ARG;
10373
10374 switch (cmsContentType) {
10375 case ENVELOPED_DATA:
10376
10377 /* NOTE: EnvelopedData does not currently support
10378 originatorInfo or unprotectedAttributes. When either of these
10379 are added, version checking below needs to be updated to match
10380 Section 6.1 of RFC 5652 */
10381
10382 /* if RecipientInfos include pwri or ori, version is 3 */
10383 if (wc_PKCS7_RecipientListIncludesType(pkcs7, PKCS7_PWRI) ||
10384 wc_PKCS7_RecipientListIncludesType(pkcs7, PKCS7_ORI)) {
10385 version = 3;
10386 break;
10387 }
10388
10389 /* if unprotectedAttrs is absent AND all RecipientInfo structs
10390 are version 0, version is 0 */
10391 if (wc_PKCS7_RecipientListVersionsAllZero(pkcs7)) {
10392 version = 0;
10393 break;
10394 }
10395
10396 /* otherwise, version is 2 */
10397 version = 2;
10398 break;
10399
10400 default:
10401 break;
10402 }
10403
10404 return version;
10405}
10406
10407
10408/* build PKCS#7 envelopedData content type, return enveloped size */
10409int wc_PKCS7_EncodeEnvelopedData(wc_PKCS7* pkcs7, byte* output, word32 outputSz)
10410{
10411 int ret, idx = 0;
10412 int totalSz, padSz, encryptedOutSz;
10413
10414 int contentInfoSeqSz = 0, outerContentTypeSz = 0, outerContentSz;
10415 byte contentInfoSeq[MAX_SEQ_SZ];
10416 byte outerContentType[MAX_ALGO_SZ];
10417 byte outerContent[MAX_SEQ_SZ];
10418
10419 int kariVersion;
10420 int envDataSeqSz, verSz;
10421 byte envDataSeq[MAX_SEQ_SZ];
10422 byte ver[MAX_VERSION_SZ];
10423
10424 WC_RNG rng;
10425 int blockSz, blockKeySz;
10426 byte* plain = NULL;
10427 byte* encryptedContent = NULL;
10428
10429 Pkcs7EncodedRecip* tmpRecip = NULL;
10430 int recipSz, recipSetSz;
10431 byte recipSet[MAX_SET_SZ];
10432
10433 int encContentOctetSz, encContentSeqSz, contentTypeSz;
10434 int contentEncAlgoSz, ivOctetStringSz;
10435 byte encContentSeq[MAX_SEQ_SZ];
10436 byte contentType[MAX_ALGO_SZ];
10437 byte contentEncAlgo[MAX_ALGO_SZ];
10438 byte tmpIv[MAX_CONTENT_IV_SIZE];
10439 byte ivOctetString[MAX_OCTET_STR_SZ];
10440 byte encContentOctet[MAX_OCTET_STR_SZ];
10441#ifdef ASN_BER_TO_DER
10442 word32 streamSz = 0;
10443#endif
10444
10445 if (pkcs7 == NULL
10446 #ifndef ASN_BER_TO_DER
10447 || pkcs7->content == NULL
10448 #endif
10449 || pkcs7->contentSz == 0) {
10450 return BAD_FUNC_ARG;
10451 }
10452
10453#ifndef ASN_BER_TO_DER
10454 if (output == NULL || outputSz == 0) {
10455 return BAD_FUNC_ARG;
10456 }
10457#else
10458 /* if both output and callback are not set then error out */
10459 if ((output == NULL || outputSz == 0) && (pkcs7->streamOutCb == NULL)) {
10460 return BAD_FUNC_ARG;
10461 }
10462#endif
10463
10464 blockKeySz = wc_PKCS7_GetOIDKeySize(pkcs7->encryptOID);
10465 if (blockKeySz < 0)
10466 return blockKeySz;
10467
10468 blockSz = wc_PKCS7_GetOIDBlockSize(pkcs7->encryptOID);
10469 if (blockSz < 0)
10470 return blockSz;
10471
10472 if (pkcs7->contentOID != FIRMWARE_PKG_DATA) {
10473 /* outer content type */
10474 ret = wc_SetContentType(ENVELOPED_DATA, outerContentType,
10475 sizeof(outerContentType));
10476 if (ret < 0)
10477 return ret;
10478
10479 outerContentTypeSz = ret;
10480 }
10481
10482 /* generate random content encryption key */
10483 ret = PKCS7_GenerateContentEncryptionKey(pkcs7, (word32)blockKeySz);
10484 if (ret != 0) {
10485 return ret;
10486 }
10487
10488 /* build RecipientInfo, only if user manually set singleCert and size */
10489 if (pkcs7->singleCert != NULL && pkcs7->singleCertSz > 0) {
10490 switch (pkcs7->publicKeyOID) {
10491 #ifndef NO_RSA
10492 #ifdef WC_RSA_PSS
10493 case RSAPSSk:
10494 FALL_THROUGH;
10495 #endif
10496 case RSAk:
10497 ret = wc_PKCS7_AddRecipient_KTRI(pkcs7, pkcs7->singleCert,
10498 pkcs7->singleCertSz, 0);
10499 break;
10500 #endif
10501 #ifdef HAVE_ECC
10502 case ECDSAk:
10503 ret = wc_PKCS7_AddRecipient_KARI(pkcs7, pkcs7->singleCert,
10504 pkcs7->singleCertSz,
10505 pkcs7->keyWrapOID,
10506 pkcs7->keyAgreeOID, pkcs7->ukm,
10507 pkcs7->ukmSz, 0);
10508 break;
10509 #endif
10510
10511 default:
10512 WOLFSSL_MSG("Unsupported RecipientInfo public key type");
10513 return BAD_FUNC_ARG;
10514 };
10515
10516 if (ret < 0) {
10517 WOLFSSL_MSG("Failed to create RecipientInfo");
10518 return ret;
10519 }
10520 }
10521
10522 recipSz = wc_PKCS7_GetRecipientListSize(pkcs7);
10523 if (recipSz < 0) {
10524 return ret;
10525
10526 } else if (recipSz == 0) {
10527 WOLFSSL_MSG("You must add at least one CMS recipient");
10528 return PKCS7_RECIP_E;
10529 }
10530 recipSetSz = (int)SetSet((word32)recipSz, recipSet);
10531
10532 /* version, defined in Section 6.1 of RFC 5652 */
10533 kariVersion = wc_PKCS7_GetCMSVersion(pkcs7, ENVELOPED_DATA);
10534 if (kariVersion < 0) {
10535 wc_PKCS7_FreeEncodedRecipientSet(pkcs7);
10536 WOLFSSL_MSG("Failed to set CMS EnvelopedData version");
10537 return PKCS7_RECIP_E;
10538 }
10539
10540 verSz = SetMyVersion((word32)kariVersion, ver, 0);
10541
10542 ret = wc_InitRng_ex(&rng, pkcs7->heap, pkcs7->devId);
10543 if (ret != 0) {
10544 wc_PKCS7_FreeEncodedRecipientSet(pkcs7);
10545 return ret;
10546 }
10547
10548 /* generate IV for block cipher */
10549 ret = wc_PKCS7_GenerateBlock(pkcs7, &rng, tmpIv, (word32)blockSz);
10550 wc_FreeRng(&rng);
10551 if (ret != 0) {
10552 wc_PKCS7_FreeEncodedRecipientSet(pkcs7);
10553 return ret;
10554 }
10555
10556 /* EncryptedContentInfo */
10557 ret = wc_SetContentType(pkcs7->contentOID, contentType,
10558 sizeof(contentType));
10559 if (ret < 0) {
10560 wc_PKCS7_FreeEncodedRecipientSet(pkcs7);
10561 return ret;
10562 }
10563
10564 contentTypeSz = ret;
10565
10566 /* allocate encrypted content buffer and PKCS#7 padding */
10567 padSz = wc_PKCS7_GetPadSize(pkcs7->contentSz, (word32)blockSz);
10568 if (padSz < 0) {
10569 wc_PKCS7_FreeEncodedRecipientSet(pkcs7);
10570 return padSz;
10571 }
10572
10573 encryptedOutSz = (int)pkcs7->contentSz + padSz;
10574
10575#ifdef ASN_BER_TO_DER
10576 if (pkcs7->getContentCb == NULL)
10577#endif
10578 {
10579 plain = (byte*)XMALLOC((word32)encryptedOutSz, pkcs7->heap,
10580 DYNAMIC_TYPE_PKCS7);
10581 if (plain == NULL) {
10582 wc_PKCS7_FreeEncodedRecipientSet(pkcs7);
10583 return MEMORY_E;
10584 }
10585
10586 ret = wc_PKCS7_PadData(pkcs7->content, pkcs7->contentSz, plain,
10587 (word32)encryptedOutSz, (word32)blockSz);
10588 if (ret < 0) {
10589 ForceZero(plain, (word32)encryptedOutSz);
10590 XFREE(plain, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
10591 wc_PKCS7_FreeEncodedRecipientSet(pkcs7);
10592 return ret;
10593 }
10594
10595 }
10596
10597#ifdef ASN_BER_TO_DER
10598 if (pkcs7->streamOutCb == NULL)
10599#endif
10600 {
10601 encryptedContent = (byte*)XMALLOC((word32)encryptedOutSz, pkcs7->heap,
10602 DYNAMIC_TYPE_PKCS7);
10603 if (encryptedContent == NULL) {
10604 if (plain != NULL)
10605 ForceZero(plain, (word32)encryptedOutSz);
10606 XFREE(plain, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
10607 wc_PKCS7_FreeEncodedRecipientSet(pkcs7);
10608 return MEMORY_E;
10609 }
10610 }
10611
10612 /* put together IV OCTET STRING */
10613 ivOctetStringSz = (int)SetOctetString((word32)blockSz, ivOctetString);
10614
10615 /* build up our ContentEncryptionAlgorithmIdentifier sequence,
10616 * adding (ivOctetStringSz + blockSz) for IV OCTET STRING */
10617 contentEncAlgoSz = (int)SetAlgoID(pkcs7->encryptOID, contentEncAlgo,
10618 oidBlkType, ivOctetStringSz + blockSz);
10619
10620 if (contentEncAlgoSz == 0) {
10621 XFREE(encryptedContent, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
10622 if (plain != NULL)
10623 ForceZero(plain, (word32)encryptedOutSz);
10624 XFREE(plain, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
10625 wc_PKCS7_FreeEncodedRecipientSet(pkcs7);
10626 return BAD_FUNC_ARG;
10627 }
10628
10629 encContentOctetSz = (int)SetImplicit(ASN_OCTET_STRING, 0,
10630 (word32)encryptedOutSz, encContentOctet, pkcs7->encodeStream);
10631 encContentSeqSz = (int)SetSequenceEx((word32)(contentTypeSz +
10632 contentEncAlgoSz + ivOctetStringSz + blockSz +
10633 encContentOctetSz + encryptedOutSz),
10634 encContentSeq, pkcs7->encodeStream);
10635
10636 /* keep track of sizes for outer wrapper layering */
10637 totalSz = verSz + recipSetSz + recipSz + encContentSeqSz + contentTypeSz +
10638 contentEncAlgoSz + ivOctetStringSz + blockSz +
10639 encContentOctetSz + encryptedOutSz;
10640
10641 /* EnvelopedData */
10642#ifdef ASN_BER_TO_DER
10643 if (pkcs7->encodeStream) {
10644 word32 tmpIdx = 0;
10645
10646 /* account for ending of encContentOctet */
10647 totalSz += ASN_INDEF_END_SZ;
10648
10649 /* account for ending of encContentSeq */
10650 totalSz += ASN_INDEF_END_SZ;
10651
10652 /* account for asn1 syntax around octet strings */
10653 StreamOctetString(NULL, (word32)encryptedOutSz, NULL, &streamSz,
10654 &tmpIdx);
10655 totalSz += ((int)streamSz - encryptedOutSz);
10656
10657 /* resize encrypted content buffer */
10658 if (encryptedContent != NULL) {
10659 XFREE(encryptedContent, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
10660 encryptedContent = (byte*)XMALLOC(streamSz, pkcs7->heap,
10661 DYNAMIC_TYPE_PKCS7);
10662 if (encryptedContent == NULL) {
10663 if (plain != NULL)
10664 ForceZero(plain, (word32)encryptedOutSz);
10665 XFREE(plain, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
10666 wc_PKCS7_FreeEncodedRecipientSet(pkcs7);
10667 return MEMORY_E;
10668 }
10669 }
10670 }
10671#endif
10672 envDataSeqSz = (int)SetSequenceEx((word32)totalSz, envDataSeq,
10673 pkcs7->encodeStream);
10674 totalSz += envDataSeqSz;
10675#ifdef ASN_BER_TO_DER
10676 if (pkcs7->encodeStream) {
10677 totalSz += ASN_INDEF_END_SZ;
10678 }
10679#endif
10680
10681 /* outer content */
10682 outerContentSz = (int)SetExplicit(0, (word32)totalSz, outerContent,
10683 pkcs7->encodeStream);
10684#ifdef ASN_BER_TO_DER
10685 if (pkcs7->encodeStream) {
10686 totalSz += ASN_INDEF_END_SZ;
10687 }
10688#endif
10689 totalSz += outerContentTypeSz;
10690 totalSz += outerContentSz;
10691
10692 if (pkcs7->contentOID != FIRMWARE_PKG_DATA) {
10693 /* ContentInfo */
10694 contentInfoSeqSz = (int)SetSequenceEx((word32)totalSz, contentInfoSeq,
10695 pkcs7->encodeStream);
10696 totalSz += contentInfoSeqSz;
10697 #ifdef ASN_BER_TO_DER
10698 if (pkcs7->encodeStream) {
10699 totalSz += ASN_INDEF_END_SZ;
10700 }
10701 #endif
10702 }
10703
10704 if ((totalSz > (int)outputSz)
10705 #ifdef ASN_BER_TO_DER
10706 && (pkcs7->streamOutCb == NULL)
10707 #endif
10708 ) {
10709 WOLFSSL_MSG("Pkcs7_encrypt output buffer too small");
10710 XFREE(encryptedContent, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
10711 if (plain != NULL)
10712 ForceZero(plain, (word32)encryptedOutSz);
10713 XFREE(plain, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
10714 wc_PKCS7_FreeEncodedRecipientSet(pkcs7);
10715 return BUFFER_E;
10716 }
10717
10718 /* begin writing out PKCS7 bundle */
10719 if (pkcs7->contentOID != FIRMWARE_PKG_DATA) {
10720 wc_PKCS7_WriteOut(pkcs7, (output)? (output + idx) : NULL,
10721 contentInfoSeq, (word32)contentInfoSeqSz);
10722 idx += contentInfoSeqSz;
10723 wc_PKCS7_WriteOut(pkcs7, (output)? (output + idx) : NULL,
10724 outerContentType, (word32)outerContentTypeSz);
10725 idx += outerContentTypeSz;
10726 wc_PKCS7_WriteOut(pkcs7, (output)? (output + idx) : NULL,
10727 outerContent, (word32)outerContentSz);
10728 idx += outerContentSz;
10729 }
10730
10731 wc_PKCS7_WriteOut(pkcs7, (output)? (output + idx) : NULL,
10732 envDataSeq, (word32)envDataSeqSz);
10733 idx += envDataSeqSz;
10734 wc_PKCS7_WriteOut(pkcs7, (output)? (output + idx) : NULL,
10735 ver, (word32)verSz);
10736 idx += verSz;
10737 wc_PKCS7_WriteOut(pkcs7, (output)? (output + idx) : NULL,
10738 recipSet, (word32)recipSetSz);
10739 idx += recipSetSz;
10740 /* copy in recipients from list */
10741 tmpRecip = pkcs7->recipList;
10742 while (tmpRecip != NULL) {
10743 wc_PKCS7_WriteOut(pkcs7, (output)? (output + idx) : NULL,
10744 tmpRecip->recip, tmpRecip->recipSz);
10745 idx += (int)tmpRecip->recipSz;
10746 tmpRecip = tmpRecip->next;
10747 }
10748 wc_PKCS7_FreeEncodedRecipientSet(pkcs7);
10749
10750 wc_PKCS7_WriteOut(pkcs7, (output)? (output + idx) : NULL,
10751 encContentSeq, (word32)encContentSeqSz);
10752 idx += encContentSeqSz;
10753 wc_PKCS7_WriteOut(pkcs7, (output)? (output + idx) : NULL,
10754 contentType, (word32)contentTypeSz);
10755 idx += contentTypeSz;
10756 wc_PKCS7_WriteOut(pkcs7, (output)? (output + idx) : NULL,
10757 contentEncAlgo, (word32)contentEncAlgoSz);
10758 idx += contentEncAlgoSz;
10759 wc_PKCS7_WriteOut(pkcs7, (output)? (output + idx) : NULL,
10760 ivOctetString, (word32)ivOctetStringSz);
10761 idx += ivOctetStringSz;
10762 wc_PKCS7_WriteOut(pkcs7, (output)? (output + idx) : NULL,
10763 tmpIv, (word32)blockSz);
10764 idx += blockSz;
10765 wc_PKCS7_WriteOut(pkcs7, (output)? (output + idx) : NULL,
10766 encContentOctet, (word32)encContentOctetSz);
10767 idx += encContentOctetSz;
10768
10769 /* encrypt content */
10770 ret = wc_PKCS7_EncryptContent(pkcs7, pkcs7->encryptOID, pkcs7->cek,
10771 (int)pkcs7->cekSz, tmpIv, blockSz, NULL, 0, NULL, 0, plain,
10772 encryptedOutSz, encryptedContent);
10773 if (ret != 0) {
10774 XFREE(encryptedContent, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
10775
10776 if (plain != NULL)
10777 ForceZero(plain, (word32)encryptedOutSz);
10778 XFREE(plain, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
10779
10780 wc_PKCS7_FreeEncodedRecipientSet(pkcs7);
10781 return ret;
10782 }
10783
10784#ifdef ASN_BER_TO_DER
10785 /* stream the content (octet string with multiple octet elements) */
10786 if (pkcs7->encodeStream) {
10787 byte indefEnd[ASN_INDEF_END_SZ * 5];
10788 word32 localIdx = 0;
10789
10790 /* advance index past encrypted content */
10791 if (!pkcs7->streamOutCb) {
10792 wc_PKCS7_WriteOut(pkcs7, (output)? output + idx : NULL,
10793 encryptedContent, streamSz);
10794 }
10795 idx += (int)streamSz;
10796
10797 /* end of encrypted content */
10798 localIdx += SetIndefEnd(indefEnd + localIdx);
10799
10800 /* end of encrypted content info */
10801 localIdx += SetIndefEnd(indefEnd + localIdx);
10802
10803 /* end of Enveloped Data seq */
10804 localIdx += SetIndefEnd(indefEnd + localIdx);
10805
10806 /* end of outer content set */
10807 localIdx += SetIndefEnd(indefEnd + localIdx);
10808
10809 /* end of outer content info seq */
10810 localIdx += SetIndefEnd(indefEnd + localIdx);
10811
10812 wc_PKCS7_WriteOut(pkcs7, (output)? (output + idx) : NULL,
10813 indefEnd, localIdx);
10814 idx += (int)localIdx;
10815 }
10816 else
10817#endif
10818 {
10819 wc_PKCS7_WriteOut(pkcs7, (output)? (output + idx) : NULL,
10820 encryptedContent, (word32)encryptedOutSz);
10821 idx += encryptedOutSz;
10822 }
10823
10824 if (plain != NULL)
10825 ForceZero(plain, (word32)encryptedOutSz);
10826 XFREE(plain, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
10827
10828 XFREE(encryptedContent, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
10829
10830 return idx;
10831}
10832
10833#ifndef NO_RSA
10834#if !defined(NO_HMAC) && !defined(NO_SHA256)
10835/* Bleichenbacher padding-oracle mitigation for PKCS#7/CMS KTRI: produce a
10836 * WC_SHA256_DIGEST_SIZE-byte pseudo-random CEK derived from a fresh
10837 * random seed and the encrypted-key ciphertext. The output is random per
10838 * call (driven by the RNG seed); deriving via HMAC of the ciphertext
10839 * simply gives the same value within one call regardless of where it is
10840 * referenced. Called unconditionally so the work is in the timing path
10841 * regardless of RSA padding validity. */
10842static int wc_PKCS7_KtriFakeCEK(wc_PKCS7* pkcs7, const byte* encryptedKey,
10843 word32 encryptedKeySz, byte* out)
10844{
10845 int ret;
10846 byte seed[WC_SHA256_DIGEST_SIZE];
10847 WC_RNG* rng = NULL;
10848 int ownRng = 0;
10849 WC_DECLARE_VAR(localRng, WC_RNG, 1, pkcs7->heap);
10850 WC_DECLARE_VAR(hmac, Hmac, 1, pkcs7->heap);
10851
10852 if (pkcs7 == NULL || encryptedKey == NULL || out == NULL) {
10853 return BAD_FUNC_ARG;
10854 }
10855
10856 WC_ALLOC_VAR_EX(hmac, Hmac, 1, pkcs7->heap, DYNAMIC_TYPE_HMAC,
10857 return MEMORY_E);
10858
10859 /* Prefer a caller-provided RNG to avoid paying a DRBG init/reseed cost
10860 * on every decrypt (and to keep the timing envelope flatter on FIPS /
10861 * HW-RNG builds). Fall back to a one-shot RNG when pkcs7->rng is not
10862 * set. */
10863 if (pkcs7->rng != NULL) {
10864 rng = pkcs7->rng;
10865 }
10866 else {
10867 WC_ALLOC_VAR_EX(localRng, WC_RNG, 1, pkcs7->heap, DYNAMIC_TYPE_RNG,
10868 WC_FREE_VAR_EX(hmac, pkcs7->heap, DYNAMIC_TYPE_HMAC);
10869 return MEMORY_E);
10870 ret = wc_InitRng_ex(localRng, pkcs7->heap, pkcs7->devId);
10871 if (ret != 0) {
10872 WC_FREE_VAR_EX(localRng, pkcs7->heap, DYNAMIC_TYPE_RNG);
10873 WC_FREE_VAR_EX(hmac, pkcs7->heap, DYNAMIC_TYPE_HMAC);
10874 return ret;
10875 }
10876 rng = localRng;
10877 ownRng = 1;
10878 }
10879
10880 ret = wc_RNG_GenerateBlock(rng, seed, (word32)sizeof(seed));
10881
10882 if (ownRng) {
10883 wc_FreeRng(localRng);
10884 WC_FREE_VAR_EX(localRng, pkcs7->heap, DYNAMIC_TYPE_RNG);
10885 }
10886
10887 if (ret != 0) {
10888 WC_FREE_VAR_EX(hmac, pkcs7->heap, DYNAMIC_TYPE_HMAC);
10889 return ret;
10890 }
10891
10892 ret = wc_HmacInit(hmac, pkcs7->heap, pkcs7->devId);
10893 if (ret == 0) {
10894 ret = wc_HmacSetKey(hmac, WC_SHA256, seed, (word32)sizeof(seed));
10895 if (ret == 0) {
10896 ret = wc_HmacUpdate(hmac, encryptedKey, encryptedKeySz);
10897 }
10898 if (ret == 0) {
10899 ret = wc_HmacFinal(hmac, out);
10900 }
10901 wc_HmacFree(hmac);
10902 }
10903 ForceZero(seed, sizeof(seed));
10904 WC_FREE_VAR_EX(hmac, pkcs7->heap, DYNAMIC_TYPE_HMAC);
10905 return ret;
10906}
10907#endif /* !NO_HMAC && !NO_SHA256 */
10908
10909/* decode KeyTransRecipientInfo (ktri), return 0 on success, <0 on error */
10910static int wc_PKCS7_DecryptKtri(wc_PKCS7* pkcs7, byte* in, word32 inSz,
10911 word32* idx, byte* decryptedKey,
10912 word32* decryptedKeySz, int* recipFound)
10913{
10914 int length, encryptedKeySz = 0, ret = 0;
10915 int keySz, version, sidType = 0;
10916 int keyIdSize;
10917 word32 encOID = 0;
10918 word32 keyIdx;
10919 byte issuerHash[KEYID_SIZE];
10920 byte* outKey = NULL;
10921 byte* pkiMsg = in;
10922 word32 pkiMsgSz = inSz;
10923 byte tag;
10924
10925#ifndef WC_NO_RSA_OAEP
10926 word32 outKeySz = 0;
10927#endif
10928#ifndef NO_PKCS7_STREAM
10929 word32 tmpIdx = *idx;
10930#endif
10931#ifdef WC_RSA_BLINDING
10932 WC_RNG rng;
10933#endif
10934
10935 byte* encryptedKey = NULL;
10936
10937#ifdef WOLFSSL_SMALL_STACK
10938 mp_int* serialNum = NULL;
10939 RsaKey* privKey = NULL;
10940#else
10941 mp_int serialNum[1];
10942 RsaKey privKey[1];
10943#endif
10944 XMEMSET(issuerHash, 0, sizeof(issuerHash));
10945
10946#if defined(WOLFSSL_SM2) && defined(WOLFSSL_SM3)
10947 keyIdSize = wc_HashGetDigestSize(wc_HashTypeConvert(HashIdAlg(
10948 pkcs7->publicKeyOID)));
10949#else
10950 keyIdSize = KEYID_SIZE;
10951#endif
10952
10953 switch (pkcs7->state) {
10954 case WC_PKCS7_DECRYPT_KTRI:
10955 #ifndef NO_PKCS7_STREAM
10956 if ((ret = wc_PKCS7_AddDataToStream(pkcs7, in, inSz, MAX_VERSION_SZ,
10957 &pkiMsg, idx)) != 0) {
10958 return ret;
10959 }
10960 pkiMsgSz = (pkcs7->stream->length > 0)? pkcs7->stream->length: inSz;
10961 #endif
10962 if (GetMyVersion(pkiMsg, idx, &version, pkiMsgSz) < 0)
10963 return ASN_PARSE_E;
10964
10965 if (version == 0) {
10966 sidType = CMS_ISSUER_AND_SERIAL_NUMBER;
10967 } else if (version == 2) {
10968 sidType = CMS_SKID;
10969 } else {
10970 return ASN_VERSION_E;
10971 }
10972
10973 #ifndef NO_PKCS7_STREAM
10974 if ((ret = wc_PKCS7_StreamEndCase(pkcs7, &tmpIdx, idx)) != 0) {
10975 break;
10976 }
10977 wc_PKCS7_StreamStoreVar(pkcs7, 0, sidType, version);
10978
10979 /* @TODO getting total amount left because of GetInt call later on
10980 * this could be optimized to stream better */
10981 if (pkcs7->stream->totalRd > pkcs7->stream->maxLen) {
10982 WOLFSSL_MSG("PKCS7 read more than expected");
10983 ret = BUFFER_E;
10984 break;
10985 }
10986 #endif
10987 wc_PKCS7_ChangeState(pkcs7, WC_PKCS7_DECRYPT_KTRI_2);
10988 FALL_THROUGH;
10989
10990 case WC_PKCS7_DECRYPT_KTRI_2:
10991 #ifndef NO_PKCS7_STREAM
10992
10993 if ((ret = wc_PKCS7_AddDataToStream(pkcs7, in, inSz,
10994 pkcs7->stream->expected, &pkiMsg, idx)) != 0) {
10995 return ret;
10996 }
10997
10998 if (in != pkiMsg) {
10999 pkiMsgSz = pkcs7->stream->length;
11000 }
11001
11002 wc_PKCS7_StreamGetVar(pkcs7, NULL, &sidType, &version);
11003
11004 /* @TODO get expected size for next part, does not account for
11005 * GetInt call well */
11006 if (pkcs7->stream->expected == MAX_SEQ_SZ) {
11007 int sz;
11008 word32 lidx;
11009
11010 if (sidType == CMS_ISSUER_AND_SERIAL_NUMBER) {
11011 lidx = *idx;
11012 ret = GetSequence(pkiMsg, &lidx, &sz, pkiMsgSz);
11013 if (ret < 0)
11014 return ret;
11015 }
11016 else {
11017 lidx = *idx + ASN_TAG_SZ;
11018 ret = GetLength(pkiMsg, &lidx, &sz, pkiMsgSz);
11019 if (ret < 0)
11020 return ret;
11021 }
11022
11023 pkcs7->stream->expected = (word32)sz + MAX_ALGO_SZ + ASN_TAG_SZ +
11024 MAX_LENGTH_SZ + 512;
11025 if (pkcs7->stream->length > 0 &&
11026 pkcs7->stream->length < pkcs7->stream->expected) {
11027 return WC_PKCS7_WANT_READ_E;
11028 }
11029 }
11030 #endif /* !NO_PKCS7_STREAM */
11031
11032 if (sidType == CMS_ISSUER_AND_SERIAL_NUMBER) {
11033
11034 /* remove IssuerAndSerialNumber */
11035 if (GetSequence(pkiMsg, idx, &length, pkiMsgSz) < 0)
11036 return ASN_PARSE_E;
11037
11038 if (GetNameHash_ex(pkiMsg, idx, issuerHash, (int)pkiMsgSz,
11039 pkcs7->publicKeyOID) < 0)
11040 return ASN_PARSE_E;
11041
11042 /* if we found correct recipient, issuer hashes will match */
11043 if (XMEMCMP(issuerHash, pkcs7->issuerHash,
11044 (word32)keyIdSize) == 0) {
11045 *recipFound = 1;
11046 }
11047
11048 WC_ALLOC_VAR_EX(serialNum, mp_int, 1, pkcs7->heap,
11049 DYNAMIC_TYPE_TMP_BUFFER, return MEMORY_E);
11050
11051 if (GetInt(serialNum, pkiMsg, idx, pkiMsgSz) < 0) {
11052 WC_FREE_VAR_EX(serialNum, pkcs7->heap,
11053 DYNAMIC_TYPE_TMP_BUFFER);
11054 return ASN_PARSE_E;
11055 }
11056
11057 mp_clear(serialNum);
11058
11059 WC_FREE_VAR_EX(serialNum, pkcs7->heap,
11060 DYNAMIC_TYPE_TMP_BUFFER);
11061
11062 } else {
11063 /* parse SubjectKeyIdentifier
11064 * RFC 5652 lists SubjectKeyIdentifier as [0] followed by
11065 * simple type of octet string
11066 *
11067 * RecipientIdentifier ::= CHOICE {
11068 * issuerAndSerialNumber IssuerAndSerialNumber,
11069 * subjectKeyIdentifier [0] SubjectKeyIdentifier }
11070 *
11071 * The choice of subjectKeyIdentifier (where version was 2) is
11072 * context specific with tag number 0 within the class.
11073 */
11074
11075 if (GetASNTag(pkiMsg, idx, &tag, pkiMsgSz) < 0)
11076 return ASN_PARSE_E;
11077
11078 /* should be context specific and tag number 0: [0] (0x80) */
11079 if (tag != ASN_CONTEXT_SPECIFIC) {
11080 return ASN_PARSE_E;
11081 }
11082
11083 if (GetLength(pkiMsg, idx, &length, pkiMsgSz) < 0)
11084 return ASN_PARSE_E;
11085
11086 /* Validate SKID container is within buffer */
11087 if ((word32)length > pkiMsgSz - (*idx))
11088 return BUFFER_E;
11089
11090 /* if we found correct recipient, SKID will match */
11091 if (length == keyIdSize &&
11092 XMEMCMP(pkiMsg + (*idx), pkcs7->issuerSubjKeyId,
11093 (word32)keyIdSize) == 0) {
11094 *recipFound = 1;
11095 }
11096 (*idx) += (word32)length;
11097 }
11098
11099 if (GetAlgoId(pkiMsg, idx, &encOID, oidKeyType, pkiMsgSz) < 0)
11100 return ASN_PARSE_E;
11101
11102 /* key encryption algorithm must be RSA for now */
11103 if (encOID != RSAk
11104 #ifndef WC_NO_RSA_OAEP
11105 && encOID != RSAESOAEPk
11106 #endif
11107 )
11108 return ALGO_ID_E;
11109
11110 #ifndef WC_NO_RSA_OAEP
11111 if (encOID == RSAESOAEPk) {
11112 if (GetSequence(pkiMsg, idx, &length, pkiMsgSz) < 0) {
11113 return ASN_PARSE_E;
11114 }
11115 if (length > 0) {
11116 WOLFSSL_MSG("only supported default OAEP");
11117 WOLFSSL_ERROR(ALGO_ID_E);
11118 return ALGO_ID_E;
11119 }
11120 }
11121 #endif
11122
11123 /* read encryptedKey */
11124 if (GetASNTag(pkiMsg, idx, &tag, pkiMsgSz) < 0)
11125 return ASN_PARSE_E;
11126
11127 if (tag != ASN_OCTET_STRING)
11128 return ASN_PARSE_E;
11129
11130 if (GetLength(pkiMsg, idx, &encryptedKeySz, pkiMsgSz) < 0) {
11131 return ASN_PARSE_E;
11132 }
11133 if (encryptedKeySz > MAX_ENCRYPTED_KEY_SZ) {
11134 return BUFFER_E;
11135 }
11136
11137 #ifndef NO_PKCS7_STREAM
11138 if ((ret = wc_PKCS7_StreamEndCase(pkcs7, &tmpIdx, idx)) != 0) {
11139 break;
11140 }
11141 wc_PKCS7_StreamStoreVar(pkcs7, (word32)encryptedKeySz, sidType,
11142 version);
11143 pkcs7->stream->expected = (word32)encryptedKeySz;
11144 #endif
11145 wc_PKCS7_ChangeState(pkcs7, WC_PKCS7_DECRYPT_KTRI_3);
11146 FALL_THROUGH;
11147
11148 case WC_PKCS7_DECRYPT_KTRI_3:
11149 #ifndef NO_PKCS7_STREAM
11150 if ((ret = wc_PKCS7_AddDataToStream(pkcs7, in, inSz,
11151 pkcs7->stream->expected, &pkiMsg, idx)) != 0) {
11152 return ret;
11153 }
11154 encryptedKeySz = (int)pkcs7->stream->expected;
11155 #endif
11156
11157 /* Always allocate to ensure aligned use with RSA */
11158 encryptedKey = (byte*)XMALLOC((word32)encryptedKeySz, pkcs7->heap,
11159 DYNAMIC_TYPE_WOLF_BIGINT);
11160 if (encryptedKey == NULL)
11161 return MEMORY_E;
11162
11163 if (*recipFound == 1)
11164 XMEMCPY(encryptedKey, &pkiMsg[*idx], (word32)encryptedKeySz);
11165 *idx += (word32)encryptedKeySz;
11166
11167 /* If this is not the correct recipient then do not try to decode
11168 * the encrypted key */
11169 if (*recipFound == 0) {
11170 XFREE(encryptedKey, pkcs7->heap, DYNAMIC_TYPE_WOLF_BIGINT);
11171 ret = PKCS7_RECIP_E;
11172 break;
11173 }
11174
11175 /* load private key */
11176 #ifdef WOLFSSL_SMALL_STACK
11177 privKey = (RsaKey*)XMALLOC(sizeof(RsaKey), pkcs7->heap,
11178 DYNAMIC_TYPE_TMP_BUFFER);
11179 if (privKey == NULL) {
11180 XFREE(encryptedKey, pkcs7->heap, DYNAMIC_TYPE_WOLF_BIGINT);
11181 return MEMORY_E;
11182 }
11183 #endif
11184
11185 ret = wc_InitRsaKey_ex(privKey, pkcs7->heap, pkcs7->devId);
11186 if (ret != 0) {
11187 XFREE(encryptedKey, pkcs7->heap, DYNAMIC_TYPE_WOLF_BIGINT);
11188 WC_FREE_VAR_EX(privKey, pkcs7->heap,
11189 DYNAMIC_TYPE_TMP_BUFFER);
11190 return ret;
11191 }
11192
11193 if (pkcs7->privateKey != NULL && pkcs7->privateKeySz > 0) {
11194 keyIdx = 0;
11195 ret = wc_RsaPrivateKeyDecode(pkcs7->privateKey, &keyIdx,
11196 privKey, pkcs7->privateKeySz);
11197 }
11198 else if (pkcs7->devId == INVALID_DEVID) {
11199 ret = BAD_FUNC_ARG;
11200 }
11201 if (ret != 0) {
11202 WOLFSSL_MSG("Failed to decode RSA private key");
11203 wc_FreeRsaKey(privKey);
11204 XFREE(encryptedKey, pkcs7->heap, DYNAMIC_TYPE_WOLF_BIGINT);
11205 WC_FREE_VAR_EX(privKey, pkcs7->heap,
11206 DYNAMIC_TYPE_TMP_BUFFER);
11207 return ret;
11208 }
11209
11210 /* decrypt encryptedKey */
11211 #ifdef WC_RSA_BLINDING
11212 ret = wc_InitRng_ex(&rng, pkcs7->heap, pkcs7->devId);
11213 if (ret == 0) {
11214 ret = wc_RsaSetRNG(privKey, &rng);
11215 }
11216 #endif
11217 if (ret == 0) {
11218 #ifdef WOLFSSL_ASYNC_CRYPT
11219 /* Currently the call to RSA decrypt here is blocking @TODO */
11220 keySz = 0; /* set initial "ret" value to 0 */
11221 do {
11222 keySz = wc_AsyncWait(keySz, &privKey->asyncDev,
11223 WC_ASYNC_FLAG_CALL_AGAIN);
11224 if (keySz >= 0)
11225 #endif
11226 {
11227 #ifndef WC_NO_RSA_OAEP
11228 if (encOID != RSAESOAEPk) {
11229 #endif
11230 keySz = wc_RsaPrivateDecryptInline(encryptedKey,
11231 (word32)encryptedKeySz, &outKey,
11232 privKey);
11233 #ifndef WC_NO_RSA_OAEP
11234 }
11235 else {
11236 outKeySz = (word32)wc_RsaEncryptSize(privKey);
11237 outKey = (byte*)XMALLOC(outKeySz, pkcs7->heap,
11238 DYNAMIC_TYPE_TMP_BUFFER);
11239 if (!outKey) {
11240 WOLFSSL_MSG("Failed to allocate out key buffer");
11241 wc_FreeRsaKey(privKey);
11242 XFREE(encryptedKey, pkcs7->heap,
11243 DYNAMIC_TYPE_WOLF_BIGINT);
11244 WC_FREE_VAR_EX(privKey, pkcs7->heap,
11245 DYNAMIC_TYPE_TMP_BUFFER);
11246 WOLFSSL_ERROR_VERBOSE(MEMORY_E);
11247 return MEMORY_E;
11248 }
11249
11250 keySz = wc_RsaPrivateDecrypt_ex(encryptedKey,
11251 (word32)encryptedKeySz, outKey, outKeySz,
11252 privKey, WC_RSA_OAEP_PAD, WC_HASH_TYPE_SHA,
11253 WC_MGF1SHA1, NULL, 0);
11254 }
11255 #endif
11256 }
11257 #ifdef WOLFSSL_ASYNC_CRYPT
11258 } while (keySz == WC_NO_ERR_TRACE(WC_PENDING_E));
11259 #endif
11260 #ifdef WC_RSA_BLINDING
11261 wc_FreeRng(&rng);
11262 #endif
11263 } else {
11264 keySz = ret;
11265 }
11266 wc_FreeRsaKey(privKey);
11267
11268 #if !defined(NO_HMAC) && !defined(NO_SHA256)
11269 {
11270 /* Bleichenbacher padding-oracle mitigation: always compute
11271 * a pseudo-random fallback CEK so timing and error
11272 * behaviour do not depend on RSA padding validity. On
11273 * unwrap failure we substitute the fallback and let
11274 * content decryption fail indistinguishably from "unwrap
11275 * succeeded but CEK is wrong". */
11276 byte fakeKey[WC_SHA256_DIGEST_SIZE];
11277 int fakeRet = wc_PKCS7_KtriFakeCEK(pkcs7, encryptedKey,
11278 (word32)encryptedKeySz,
11279 fakeKey);
11280
11281 if (fakeRet != 0) {
11282 /* Fallback generation failed (e.g. RNG/HMAC error).
11283 * Return the fallback-generation status, which does
11284 * not depend on RSA padding validity, rather than the
11285 * RSA status which would re-open the oracle. */
11286 ForceZero(fakeKey, sizeof(fakeKey));
11287 /* In the non-OAEP path RSA is decrypted in-place via
11288 * wc_RsaPrivateDecryptInline, so encryptedKey holds
11289 * the (possibly valid) plaintext CEK. Zero it before
11290 * free. */
11291 ForceZero(encryptedKey, (word32)encryptedKeySz);
11292 XFREE(encryptedKey, pkcs7->heap, DYNAMIC_TYPE_WOLF_BIGINT);
11293 WC_FREE_VAR_EX(privKey, pkcs7->heap,
11294 DYNAMIC_TYPE_TMP_BUFFER);
11295 #ifndef WC_NO_RSA_OAEP
11296 if (encOID == RSAESOAEPk) {
11297 if (outKey != NULL) {
11298 ForceZero(outKey, outKeySz);
11299 XFREE(outKey, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
11300 }
11301 }
11302 #endif
11303 return fakeRet;
11304 }
11305
11306 /* Constant-time select between fake and real CEK. On RSA
11307 * failure outKey may be NULL or keySz may be <= 0; in
11308 * both cases the mask selects fakeKey for every byte.
11309 *
11310 * To avoid data-dependent branches that leak realLen,
11311 * copy the real key into a fixed-size zero-padded buffer
11312 * first, then select byte-by-byte in constant time. */
11313 {
11314 word32 i;
11315 byte useFake;
11316 int realLen = keySz;
11317 byte realPad[WC_SHA256_DIGEST_SIZE];
11318
11319 XMEMSET(realPad, 0, sizeof(realPad));
11320 /* Constant-time copy: avoid data-dependent branches
11321 * that could leak whether RSA padding was valid.
11322 * When outKey is NULL (inline RSA failure), use
11323 * encryptedKey as a safe readable source; the mask
11324 * will zero out all bytes anyway. Both encryptedKey
11325 * and outKey (when non-NULL) are at least
11326 * sizeof(realPad) bytes for any RSA key size.
11327 *
11328 * Use constant-time pointer selection to avoid
11329 * branching on outKey nullity, which would leak
11330 * whether RSA PKCS#1 v1.5 padding was valid. */
11331 {
11332 byte haveSrc = ctMaskGTE(realLen, 1);
11333 const byte* srcTbl[2];
11334 const byte* src;
11335 word32 j = 0;
11336 word32 safeJ = 0;
11337
11338 /* Select source without integer pointer synthesis.
11339 * Some safety-oriented compilers (e.g. Fil-C) treat
11340 * int-to-pointer reconstruction as a null-object
11341 * pointer on dereference. */
11342 srcTbl[0] = encryptedKey;
11343 srcTbl[1] = outKey;
11344 src = srcTbl[haveSrc & 1];
11345
11346 /* safeJ is clamped to max(0, realLen-1): it
11347 * only advances while the next index would
11348 * still be inside realLen, so src[safeJ] is
11349 * always in bounds. Bytes at j >= realLen are
11350 * masked to zero by inBounds anyway. */
11351 for (j = 0; j < (word32)sizeof(realPad); j++) {
11352 byte inBounds = ctMaskLT((int)j, realLen);
11353 byte advance = ctMaskLT((int)(safeJ + 1),
11354 realLen);
11355 realPad[j] = src[safeJ] & haveSrc & inBounds;
11356 safeJ += (word32)(advance & 1);
11357 }
11358 }
11359 useFake = ctMaskLT(realLen, 1); /* 0xFF if realLen<=0 */
11360
11361 for (i = 0; i < (word32)sizeof(fakeKey); i++) {
11362 decryptedKey[i] = ctMaskSel(useFake, fakeKey[i],
11363 realPad[i]);
11364 }
11365 /* Report the real key size on success; on RSA
11366 * failure (realLen <= 0) report sizeof(fakeKey).
11367 * Constant-time select avoids branching on RSA
11368 * padding validity. */
11369 *decryptedKeySz = (word32)ctMaskSelInt(useFake,
11370 (int)sizeof(fakeKey), realLen);
11371 ForceZero(realPad, sizeof(realPad));
11372 }
11373 ForceZero(fakeKey, sizeof(fakeKey));
11374 /* In the non-OAEP path RSA is decrypted in-place via
11375 * wc_RsaPrivateDecryptInline, so encryptedKey holds the
11376 * plaintext CEK after the unwrap. Zero it before free. */
11377 ForceZero(encryptedKey, (word32)encryptedKeySz);
11378 }
11379 #else /* NO_HMAC || NO_SHA256: mitigation unavailable */
11380 #if !defined(WOLFSSL_NO_KTRI_ORACLE_WARNING)
11381 #warning "PKCS7 KTRI Bleichenbacher mitigation requires HMAC " \
11382 "and SHA256; build without them leaves the RSA unwrap " \
11383 "error path observable to callers. " \
11384 "Define WOLFSSL_NO_KTRI_ORACLE_WARNING to silence."
11385 #endif
11386
11387 if (keySz <= 0 || outKey == NULL) {
11388 ForceZero(encryptedKey, (word32)encryptedKeySz);
11389 XFREE(encryptedKey, pkcs7->heap, DYNAMIC_TYPE_WOLF_BIGINT);
11390 WC_FREE_VAR_EX(privKey, pkcs7->heap,
11391 DYNAMIC_TYPE_TMP_BUFFER);
11392 #ifndef WC_NO_RSA_OAEP
11393 if (encOID == RSAESOAEPk) {
11394 if (outKey) {
11395 ForceZero(outKey, outKeySz);
11396 XFREE(outKey, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
11397 }
11398 }
11399 #endif
11400 return keySz;
11401 }
11402 else {
11403 *decryptedKeySz = (word32)keySz;
11404 XMEMCPY(decryptedKey, outKey, (word32)keySz);
11405 ForceZero(encryptedKey, (word32)encryptedKeySz);
11406 }
11407 #endif /* !NO_HMAC && !NO_SHA256 */
11408
11409 XFREE(encryptedKey, pkcs7->heap, DYNAMIC_TYPE_WOLF_BIGINT);
11410 WC_FREE_VAR_EX(privKey, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
11411 #ifndef WC_NO_RSA_OAEP
11412 if (encOID == RSAESOAEPk) {
11413 if (outKey) {
11414 ForceZero(outKey, outKeySz);
11415 XFREE(outKey, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
11416 }
11417 }
11418 #endif
11419 #ifndef NO_PKCS7_STREAM
11420 if ((ret = wc_PKCS7_StreamEndCase(pkcs7, &tmpIdx, idx)) != 0) {
11421 break;
11422 }
11423 #endif
11424 ret = 0; /* success */
11425 break;
11426
11427 default:
11428 WOLFSSL_MSG("PKCS7 Unknown KTRI decrypt state");
11429 ret = BAD_FUNC_ARG;
11430 }
11431
11432 return ret;
11433}
11434#endif /* !NO_RSA */
11435
11436#ifdef HAVE_ECC
11437
11438/* remove ASN.1 OriginatorIdentifierOrKey, return 0 on success, <0 on error */
11439static int wc_PKCS7_KariGetOriginatorIdentifierOrKey(WC_PKCS7_KARI* kari,
11440 byte* pkiMsg, word32 pkiMsgSz, word32* idx)
11441{
11442 int ret, length;
11443 word32 keyOID, oidSum = 0;
11444 int curve_id = ECC_CURVE_DEF;
11445 byte tag;
11446
11447 if (kari == NULL || pkiMsg == NULL || idx == NULL)
11448 return BAD_FUNC_ARG;
11449
11450 /* remove OriginatorIdentifierOrKey */
11451 if (GetASNTag(pkiMsg, idx, &tag, pkiMsgSz) == 0 &&
11452 tag == (ASN_CONSTRUCTED | ASN_CONTEXT_SPECIFIC | 0)) {
11453 if (GetLength(pkiMsg, idx, &length, pkiMsgSz) < 0)
11454 return ASN_PARSE_E;
11455
11456 } else {
11457 return ASN_PARSE_E;
11458 }
11459
11460 /* remove OriginatorPublicKey */
11461 if (GetASNTag(pkiMsg, idx, &tag, pkiMsgSz) == 0 &&
11462 tag == (ASN_CONSTRUCTED | ASN_CONTEXT_SPECIFIC | 1)) {
11463 if (GetLength(pkiMsg, idx, &length, pkiMsgSz) < 0)
11464 return ASN_PARSE_E;
11465
11466 } else {
11467 return ASN_PARSE_E;
11468 }
11469
11470 /* remove AlgorithmIdentifier */
11471 if (GetAlgoId(pkiMsg, idx, &keyOID, oidKeyType, pkiMsgSz) < 0)
11472 return ASN_PARSE_E;
11473
11474 if (keyOID != ECDSAk)
11475 return ASN_PARSE_E;
11476
11477 /* optional algorithm parameters */
11478 ret = GetObjectId(pkiMsg, idx, &oidSum, oidIgnoreType, pkiMsgSz);
11479 if (ret == 0) {
11480 /* get curve id */
11481 curve_id = wc_ecc_get_oid(oidSum, NULL, 0);
11482 if (curve_id < 0)
11483 return ECC_CURVE_OID_E;
11484 }
11485
11486 /* remove ECPoint BIT STRING */
11487 if (GetASNTag(pkiMsg, idx, &tag, pkiMsgSz) < 0)
11488 return ASN_PARSE_E;
11489
11490 if (tag != ASN_BIT_STRING)
11491 return ASN_PARSE_E;
11492
11493 if (GetLength(pkiMsg, idx, &length, pkiMsgSz) < 0)
11494 return ASN_PARSE_E;
11495
11496 /* BIT STRING must have at least unused-bits byte + 1 byte of content */
11497 if (length < 2)
11498 return ASN_PARSE_E;
11499
11500 /* Validate BIT STRING content is within input buffer */
11501 if (*idx > pkiMsgSz || (word32)length > pkiMsgSz - *idx)
11502 return ASN_PARSE_E;
11503
11504 if (GetASNTag(pkiMsg, idx, &tag, pkiMsgSz) < 0)
11505 return ASN_EXPECT_0_E;
11506
11507 if (tag != ASN_OTHER_TYPE)
11508 return ASN_EXPECT_0_E;
11509
11510 /* get sender ephemeral public ECDSA key */
11511 ret = wc_ecc_init_ex(kari->senderKey, kari->heap, kari->devId);
11512 if (ret != 0)
11513 return ret;
11514
11515 kari->senderKeyInit = 1;
11516
11517 /* length-1 for unused bits counter */
11518 ret = wc_ecc_import_x963_ex(pkiMsg + (*idx), (word32)length - 1,
11519 kari->senderKey, curve_id);
11520 if (ret != 0) {
11521 ret = wc_EccPublicKeyDecode(pkiMsg, idx, kari->senderKey,
11522 *idx + (word32)length - 1);
11523 if (ret != 0)
11524 return ret;
11525 }
11526 else {
11527 (*idx) += (word32)(length - 1);
11528 }
11529
11530 return 0;
11531}
11532
11533
11534/* remove optional UserKeyingMaterial if available, return 0 on success,
11535 * < 0 on error */
11536static int wc_PKCS7_KariGetUserKeyingMaterial(WC_PKCS7_KARI* kari,
11537 byte* pkiMsg, word32 pkiMsgSz, word32* idx)
11538{
11539 int length;
11540 word32 savedIdx;
11541 byte tag;
11542
11543 if (kari == NULL || pkiMsg == NULL || idx == NULL)
11544 return BAD_FUNC_ARG;
11545
11546 savedIdx = *idx;
11547
11548 /* starts with EXPLICIT [1] */
11549 if (GetASNTag(pkiMsg, idx, &tag, pkiMsgSz) < 0) {
11550 *idx = savedIdx;
11551 return 0;
11552 }
11553 if (tag != (ASN_CONSTRUCTED | ASN_CONTEXT_SPECIFIC | 1)) {
11554 *idx = savedIdx;
11555 return 0;
11556 }
11557
11558 if (GetLength(pkiMsg, idx, &length, pkiMsgSz) < 0) {
11559 *idx = savedIdx;
11560 return 0;
11561 }
11562
11563 /* get OCTET STRING */
11564 if (GetASNTag(pkiMsg, idx, &tag, pkiMsgSz) < 0) {
11565 *idx = savedIdx;
11566 return 0;
11567 }
11568 if (tag != ASN_OCTET_STRING) {
11569 *idx = savedIdx;
11570 return 0;
11571 }
11572
11573 if (GetLength(pkiMsg, idx, &length, pkiMsgSz) < 0) {
11574 *idx = savedIdx;
11575 return 0;
11576 }
11577
11578 kari->ukm = NULL;
11579 if (length > 0) {
11580 kari->ukm = (byte*)XMALLOC((word32)length, kari->heap,
11581 DYNAMIC_TYPE_PKCS7);
11582 if (kari->ukm == NULL)
11583 return MEMORY_E;
11584
11585 XMEMCPY(kari->ukm, pkiMsg + (*idx), (word32)length);
11586 kari->ukmOwner = 1;
11587 }
11588
11589 (*idx) += (word32)length;
11590 kari->ukmSz = (word32)length;
11591
11592 return 0;
11593}
11594
11595
11596/* remove ASN.1 KeyEncryptionAlgorithmIdentifier, return 0 on success,
11597 * < 0 on error */
11598static int wc_PKCS7_KariGetKeyEncryptionAlgorithmId(WC_PKCS7_KARI* kari,
11599 byte* pkiMsg, word32 pkiMsgSz, word32* idx,
11600 word32* keyAgreeOID, word32* keyWrapOID)
11601{
11602 int length = 0;
11603 word32 localIdx;
11604
11605 if (kari == NULL || pkiMsg == NULL || idx == NULL ||
11606 keyAgreeOID == NULL || keyWrapOID == NULL)
11607 return BAD_FUNC_ARG;
11608
11609 localIdx = *idx;
11610
11611 /* remove KeyEncryptionAlgorithmIdentifier */
11612 if (GetSequence(pkiMsg, &localIdx, &length, pkiMsgSz) < 0)
11613 return ASN_PARSE_E;
11614
11615 localIdx = *idx;
11616 if (GetAlgoId(pkiMsg, &localIdx, keyAgreeOID, oidCmsKeyAgreeType,
11617 pkiMsgSz) < 0) {
11618 return ASN_PARSE_E;
11619 }
11620
11621 if (localIdx < *idx + (word32)length) {
11622 *idx = localIdx;
11623 }
11624 /* remove KeyWrapAlgorithm, stored in parameter of KeyEncAlgoId */
11625 if (GetAlgoId(pkiMsg, idx, keyWrapOID, oidKeyWrapType, pkiMsgSz) < 0)
11626 return ASN_PARSE_E;
11627
11628 return 0;
11629}
11630
11631
11632/* remove ASN.1 SubjectKeyIdentifier, return 0 on success, < 0 on error
11633 * if subject key ID matches, recipFound is set to 1 */
11634static int wc_PKCS7_KariGetSubjectKeyIdentifier(WC_PKCS7_KARI* kari,
11635 byte* pkiMsg, word32 pkiMsgSz, word32* idx,
11636 int* recipFound, byte* rid)
11637{
11638 int length;
11639 byte tag;
11640 int keyIdSize;
11641
11642 if (kari == NULL || pkiMsg == NULL || idx == NULL || recipFound == NULL ||
11643 rid == NULL)
11644 return BAD_FUNC_ARG;
11645
11646#if defined(WOLFSSL_SM2) && defined(WOLFSSL_SM3)
11647 keyIdSize = wc_HashGetDigestSize(wc_HashTypeConvert(HashIdAlg(
11648 kari->decoded->signatureOID)));
11649#else
11650 keyIdSize = KEYID_SIZE;
11651#endif
11652
11653 /* remove RecipientKeyIdentifier IMPLICIT [0] */
11654 if (GetASNTag(pkiMsg, idx, &tag, pkiMsgSz) < 0) {
11655 return ASN_PARSE_E;
11656 }
11657
11658 if (tag == (ASN_CONSTRUCTED | ASN_CONTEXT_SPECIFIC | 0)) {
11659 if (GetLength(pkiMsg, idx, &length, pkiMsgSz) < 0)
11660 return ASN_PARSE_E;
11661
11662 } else {
11663 return ASN_PARSE_E;
11664 }
11665
11666 /* remove SubjectKeyIdentifier */
11667 if (GetASNTag(pkiMsg, idx, &tag, pkiMsgSz) < 0) {
11668 return ASN_PARSE_E;
11669 }
11670
11671 if (tag != ASN_OCTET_STRING)
11672 return ASN_PARSE_E;
11673
11674 if (GetLength(pkiMsg, idx, &length, pkiMsgSz) < 0)
11675 return ASN_PARSE_E;
11676
11677 if (length != keyIdSize)
11678 return ASN_PARSE_E;
11679
11680 XMEMCPY(rid, pkiMsg + (*idx), (word32)keyIdSize);
11681 (*idx) += (word32)length;
11682
11683 /* subject key id should match if recipient found */
11684 if (XMEMCMP(rid, kari->decoded->extSubjKeyId, (word32)keyIdSize) == 0) {
11685 *recipFound = 1;
11686 }
11687
11688 return 0;
11689}
11690
11691
11692/* remove ASN.1 IssuerAndSerialNumber, return 0 on success, < 0 on error
11693 * if issuer and serial number match, recipFound is set to 1 */
11694static int wc_PKCS7_KariGetIssuerAndSerialNumber(WC_PKCS7_KARI* kari,
11695 byte* pkiMsg, word32 pkiMsgSz, word32* idx,
11696 int* recipFound, byte* rid)
11697{
11698 int length, ret;
11699 int keyIdSize;
11700#ifdef WOLFSSL_SMALL_STACK
11701 mp_int* serial;
11702 mp_int* recipSerial;
11703#else
11704 mp_int serial[1];
11705 mp_int recipSerial[1];
11706#endif
11707
11708 if (rid == NULL) {
11709 return BAD_FUNC_ARG;
11710 }
11711
11712#if defined(WOLFSSL_SM2) && defined(WOLFSSL_SM3)
11713 keyIdSize = wc_HashGetDigestSize(wc_HashTypeConvert(HashIdAlg(
11714 kari->decoded->signatureOID)));
11715#else
11716 keyIdSize = KEYID_SIZE;
11717#endif
11718
11719 /* remove IssuerAndSerialNumber */
11720 if (GetSequence(pkiMsg, idx, &length, pkiMsgSz) < 0)
11721 return ASN_PARSE_E;
11722
11723 if (GetNameHash_ex(pkiMsg, idx, rid, (int)pkiMsgSz,
11724 kari->decoded->signatureOID) < 0) {
11725 return ASN_PARSE_E;
11726 }
11727
11728 /* if we found correct recipient, issuer hashes will match */
11729 if (kari->decodedInit == 1) {
11730 if (XMEMCMP(rid, kari->decoded->issuerHash, (word32)keyIdSize) == 0) {
11731 *recipFound = 1;
11732 }
11733 }
11734 else {
11735 /* can not confirm recipient serial number with no cert provided */
11736 WOLFSSL_MSG("No recipient cert loaded to match with CMS serial number");
11737 *recipFound = 1;
11738 }
11739
11740#ifdef WOLFSSL_SMALL_STACK
11741 serial = (mp_int*)XMALLOC(sizeof(mp_int), kari->heap,
11742 DYNAMIC_TYPE_TMP_BUFFER);
11743 if (serial == NULL)
11744 return MEMORY_E;
11745
11746 recipSerial = (mp_int*)XMALLOC(sizeof(mp_int), kari->heap,
11747 DYNAMIC_TYPE_TMP_BUFFER);
11748 if (recipSerial == NULL) {
11749 XFREE(serial, kari->heap, DYNAMIC_TYPE_TMP_BUFFER);
11750 return MEMORY_E;
11751 }
11752#endif
11753
11754 if (GetInt(serial, pkiMsg, idx, pkiMsgSz) < 0) {
11755 WC_FREE_VAR_EX(serial, kari->heap, DYNAMIC_TYPE_TMP_BUFFER);
11756 WC_FREE_VAR_EX(recipSerial, kari->heap, DYNAMIC_TYPE_TMP_BUFFER);
11757 return ASN_PARSE_E;
11758 }
11759
11760 ret = mp_init(recipSerial);
11761 if (ret == MP_OKAY)
11762 ret = mp_read_unsigned_bin(recipSerial, kari->decoded->serial,
11763 (word32)kari->decoded->serialSz);
11764 if (ret != MP_OKAY) {
11765 mp_clear(serial);
11766 WOLFSSL_MSG("Failed to parse CMS recipient serial number");
11767 WC_FREE_VAR_EX(serial, kari->heap, DYNAMIC_TYPE_TMP_BUFFER);
11768 WC_FREE_VAR_EX(recipSerial, kari->heap, DYNAMIC_TYPE_TMP_BUFFER);
11769 return ret;
11770 }
11771
11772 if (kari->decodedInit == 1 &&
11773 mp_cmp(recipSerial, serial) != MP_EQ) {
11774 mp_clear(serial);
11775 mp_clear(recipSerial);
11776 WOLFSSL_MSG("CMS serial number does not match recipient");
11777 WC_FREE_VAR_EX(serial, kari->heap, DYNAMIC_TYPE_TMP_BUFFER);
11778 WC_FREE_VAR_EX(recipSerial, kari->heap, DYNAMIC_TYPE_TMP_BUFFER);
11779 return PKCS7_RECIP_E;
11780 }
11781
11782 mp_clear(serial);
11783 mp_clear(recipSerial);
11784
11785 WC_FREE_VAR_EX(serial, kari->heap, DYNAMIC_TYPE_TMP_BUFFER);
11786 WC_FREE_VAR_EX(recipSerial, kari->heap, DYNAMIC_TYPE_TMP_BUFFER);
11787
11788 return 0;
11789}
11790
11791
11792/* remove ASN.1 RecipientEncryptedKeys, return 0 on success, < 0 on error */
11793static int wc_PKCS7_KariGetRecipientEncryptedKeys(WC_PKCS7_KARI* kari,
11794 byte* pkiMsg, word32 pkiMsgSz, word32* idx,
11795 int* recipFound, byte* encryptedKey,
11796 int* encryptedKeySz, byte* rid)
11797{
11798 int length;
11799 int ret = 0;
11800 byte tag;
11801 word32 localIdx;
11802
11803 if (kari == NULL || pkiMsg == NULL || idx == NULL ||
11804 recipFound == NULL || encryptedKey == NULL)
11805 return BAD_FUNC_ARG;
11806
11807 /* remove RecipientEncryptedKeys */
11808 if (GetSequence(pkiMsg, idx, &length, pkiMsgSz) < 0)
11809 return ASN_PARSE_E;
11810
11811 /* remove RecipientEncryptedKeys */
11812 if (GetSequence(pkiMsg, idx, &length, pkiMsgSz) < 0)
11813 return ASN_PARSE_E;
11814
11815 /* KeyAgreeRecipientIdentifier is CHOICE of IssuerAndSerialNumber
11816 * or [0] IMPLICIT RecipientKeyIdentifier */
11817 localIdx = *idx;
11818 if (GetASNTag(pkiMsg, &localIdx, &tag, pkiMsgSz) < 0)
11819 return ASN_PARSE_E;
11820
11821 if (tag == (ASN_CONSTRUCTED | ASN_CONTEXT_SPECIFIC | 0)) {
11822 /* try to get RecipientKeyIdentifier */
11823 ret = wc_PKCS7_KariGetSubjectKeyIdentifier(kari, pkiMsg, pkiMsgSz,
11824 idx, recipFound, rid);
11825 } else {
11826 /* try to get IssuerAndSerialNumber */
11827 ret = wc_PKCS7_KariGetIssuerAndSerialNumber(kari, pkiMsg, pkiMsgSz,
11828 idx, recipFound, rid);
11829 }
11830
11831 /* if we don't have either option, malformed CMS */
11832 if (ret != 0)
11833 return ret;
11834
11835 /* remove EncryptedKey */
11836 if (GetASNTag(pkiMsg, idx, &tag, pkiMsgSz) < 0)
11837 return ASN_PARSE_E;
11838
11839 if (tag != ASN_OCTET_STRING)
11840 return ASN_PARSE_E;
11841
11842 if (GetLength(pkiMsg, idx, &length, pkiMsgSz) < 0)
11843 return ASN_PARSE_E;
11844
11845 /* put encrypted CEK in decryptedKey buffer for now, decrypt later */
11846 if (length > *encryptedKeySz)
11847 return BUFFER_E;
11848
11849 XMEMCPY(encryptedKey, pkiMsg + (*idx), (word32)length);
11850 *encryptedKeySz = length;
11851 (*idx) += (word32)length;
11852
11853 return 0;
11854}
11855
11856#endif /* HAVE_ECC */
11857
11858
11859int wc_PKCS7_SetOriEncryptCtx(wc_PKCS7* pkcs7, void* ctx)
11860{
11861 if (pkcs7 == NULL)
11862 return BAD_FUNC_ARG;
11863
11864 pkcs7->oriEncryptCtx = ctx;
11865
11866 return 0;
11867}
11868
11869
11870int wc_PKCS7_SetOriDecryptCtx(wc_PKCS7* pkcs7, void* ctx)
11871{
11872
11873 if (pkcs7 == NULL)
11874 return BAD_FUNC_ARG;
11875
11876 pkcs7->oriDecryptCtx = ctx;
11877
11878 return 0;
11879}
11880
11881
11882int wc_PKCS7_SetOriDecryptCb(wc_PKCS7* pkcs7, CallbackOriDecrypt cb)
11883{
11884 if (pkcs7 == NULL)
11885 return BAD_FUNC_ARG;
11886
11887 pkcs7->oriDecryptCb = cb;
11888
11889 return 0;
11890}
11891
11892
11893/* return 0 on success */
11894int wc_PKCS7_SetWrapCEKCb(wc_PKCS7* pkcs7, CallbackWrapCEK cb)
11895{
11896 if (pkcs7 == NULL)
11897 return BAD_FUNC_ARG;
11898
11899 pkcs7->wrapCEKCb = cb;
11900
11901 return 0;
11902}
11903
11904
11905/* return 0 on success */
11906int wc_PKCS7_SetAESKeyWrapUnwrapCb(wc_PKCS7* pkcs7, CallbackAESKeyWrapUnwrap aesKeyWrapUnwrapCb)
11907{
11908 if (pkcs7 == NULL)
11909 return BAD_FUNC_ARG;
11910
11911 pkcs7->aesKeyWrapUnwrapCb = aesKeyWrapUnwrapCb;
11912
11913 return 0;
11914}
11915
11916
11917/* Decrypt ASN.1 OtherRecipientInfo (ori), as defined by:
11918 *
11919 * OtherRecipientInfo ::= SEQUENCE {
11920 * oriType OBJECT IDENTIFIER,
11921 * oriValue ANY DEFINED BY oriType }
11922 *
11923 * pkcs7 - pointer to initialized PKCS7 structure
11924 * pkiMsg - pointer to encoded CMS bundle
11925 * pkiMsgSz - size of pkiMsg, bytes
11926 * idx - [IN/OUT] pointer to index into pkiMsg
11927 * decryptedKey - [OUT] output buf for decrypted content encryption key
11928 * decryptedKeySz - [IN/OUT] size of buffer, size of decrypted key
11929 * recipFound - [OUT] 1 if recipient has been found, 0 if not
11930 *
11931 * Return 0 on success, negative upon error.
11932 */
11933static int wc_PKCS7_DecryptOri(wc_PKCS7* pkcs7, byte* in, word32 inSz,
11934 word32* idx, byte* decryptedKey,
11935 word32* decryptedKeySz, int* recipFound)
11936{
11937 int ret, seqSz, oriOIDSz;
11938 word32 oriValueSz, tmpIdx;
11939 byte* oriValue;
11940 byte oriOID[MAX_OID_SZ];
11941
11942 byte* pkiMsg = in;
11943 word32 pkiMsgSz = inSz;
11944#ifndef NO_PKCS7_STREAM
11945 word32 stateIdx = *idx;
11946#endif
11947
11948 if (pkcs7->oriDecryptCb == NULL) {
11949 WOLFSSL_MSG("You must register an ORI Decrypt callback");
11950 return BAD_FUNC_ARG;
11951 }
11952
11953 switch (pkcs7->state) {
11954
11955 case WC_PKCS7_DECRYPT_ORI:
11956 #ifndef NO_PKCS7_STREAM
11957 /* @TODO for now just get full buffer, needs divided up */
11958 if ((ret = wc_PKCS7_AddDataToStream(pkcs7, in, inSz,
11959 (pkcs7->stream->maxLen - pkcs7->stream->totalRd) +
11960 pkcs7->stream->length, &pkiMsg, idx)) != 0) {
11961 return ret;
11962 }
11963 pkiMsgSz = (pkcs7->stream->length > 0)? pkcs7->stream->length: inSz;
11964 #endif
11965 /* get OtherRecipientInfo sequence length */
11966 if (GetLength(pkiMsg, idx, &seqSz, pkiMsgSz) < 0)
11967 return ASN_PARSE_E;
11968
11969 tmpIdx = *idx;
11970
11971 /* remove and store oriType OBJECT IDENTIFIER */
11972 if (GetASNObjectId(pkiMsg, idx, &oriOIDSz, pkiMsgSz) != 0)
11973 return ASN_PARSE_E;
11974
11975 if (oriOIDSz <= 0 || (word32)oriOIDSz > MAX_OID_SZ) {
11976 WOLFSSL_MSG("ORI oriType OID too large");
11977 return ASN_PARSE_E;
11978 }
11979
11980 XMEMCPY(oriOID, pkiMsg + *idx, (word32)oriOIDSz);
11981 *idx += (word32)oriOIDSz;
11982
11983 /* Validate OID did not consume more than the SEQUENCE declared */
11984 if ((*idx - tmpIdx) > (word32)seqSz) {
11985 WOLFSSL_MSG("ORI oriType OID exceeds SEQUENCE boundary");
11986 return ASN_PARSE_E;
11987 }
11988
11989 /* get oriValue, increment idx */
11990 oriValue = pkiMsg + *idx;
11991 oriValueSz = (word32)seqSz - (*idx - tmpIdx);
11992
11993 /* Validate oriValue region is within input buffer */
11994 if (*idx > pkiMsgSz || oriValueSz > pkiMsgSz - *idx) {
11995 WOLFSSL_MSG("ORI oriValue exceeds input buffer");
11996 return ASN_PARSE_E;
11997 }
11998
11999 *idx += oriValueSz;
12000
12001 /* pass oriOID and oriValue to user callback, expect back
12002 decryptedKey and size */
12003 ret = pkcs7->oriDecryptCb(pkcs7, oriOID, (word32)oriOIDSz, oriValue,
12004 oriValueSz, decryptedKey, decryptedKeySz,
12005 pkcs7->oriDecryptCtx);
12006
12007 if (ret != 0 || decryptedKey == NULL || *decryptedKeySz == 0) {
12008 /* decrypt operation failed */
12009 *recipFound = 0;
12010 return PKCS7_RECIP_E;
12011 }
12012
12013 /* mark recipFound, since we only support one RecipientInfo for
12014 * now */
12015 *recipFound = 1;
12016
12017 #ifndef NO_PKCS7_STREAM
12018 if ((ret = wc_PKCS7_StreamEndCase(pkcs7, &stateIdx, idx)) != 0) {
12019 break;
12020 }
12021 #endif
12022 ret = 0; /* success */
12023 break;
12024
12025 default:
12026 WOLFSSL_MSG("PKCS7 ORI unknown state");
12027 ret = BAD_FUNC_ARG;
12028
12029 }
12030
12031 return ret;
12032}
12033
12034#if !defined(NO_PWDBASED) && !defined(NO_SHA)
12035
12036/* decode ASN.1 PasswordRecipientInfo (pwri), return 0 on success,
12037 * < 0 on error */
12038static int wc_PKCS7_DecryptPwri(wc_PKCS7* pkcs7, byte* in, word32 inSz,
12039 word32* idx, byte* decryptedKey,
12040 word32* decryptedKeySz, int* recipFound)
12041{
12042 byte* salt;
12043 byte* cek;
12044 byte* kek;
12045
12046 byte tmpIv[MAX_CONTENT_IV_SIZE];
12047
12048 int ret = 0, length, saltSz, iterations, blockSz, kekKeySz;
12049 int hashOID = WC_SHA; /* default to SHA1 */
12050 int keyLen = 0;
12051 int keyLenPresent = 0;
12052 word32 pbkdf2End = 0;
12053 word32 kdfAlgoId, pwriEncAlgoId, keyEncAlgoId, cekSz;
12054 byte* pkiMsg = in;
12055 word32 pkiMsgSz = inSz;
12056 byte tag;
12057#ifndef NO_PKCS7_STREAM
12058 word32 tmpIdx = *idx;
12059#endif
12060
12061 switch (pkcs7->state) {
12062 case WC_PKCS7_DECRYPT_PWRI:
12063 #ifndef NO_PKCS7_STREAM
12064 /*@TODO for now just get full buffer, needs divided up */
12065 if ((ret = wc_PKCS7_AddDataToStream(pkcs7, in, inSz,
12066 (pkcs7->stream->maxLen - pkcs7->stream->totalRd) +
12067 pkcs7->stream->length, &pkiMsg, idx)) != 0) {
12068 return ret;
12069 }
12070 #ifdef ASN_BER_TO_DER
12071 /* check if pkcs7->der is being used after BER to DER */
12072 if (pkcs7->derSz > 0) {
12073 pkiMsgSz = pkcs7->derSz;
12074 }
12075 else
12076 #endif
12077 {
12078 pkiMsgSz = (pkcs7->stream->length > 0)? pkcs7->stream->length:
12079 inSz;
12080 }
12081 #endif
12082 /* remove KeyDerivationAlgorithmIdentifier */
12083 if (GetASNTag(pkiMsg, idx, &tag, pkiMsgSz) < 0)
12084 return ASN_PARSE_E;
12085
12086 if (tag != (ASN_CONSTRUCTED | ASN_CONTEXT_SPECIFIC | 0))
12087 return ASN_PARSE_E;
12088
12089 if (GetLength(pkiMsg, idx, &length, pkiMsgSz) < 0)
12090 return ASN_PARSE_E;
12091
12092 /* get KeyDerivationAlgorithmIdentifier */
12093 if (wc_GetContentType(pkiMsg, idx, &kdfAlgoId, pkiMsgSz) < 0)
12094 return ASN_PARSE_E;
12095
12096 /* get KDF params SEQ */
12097 if (GetSequence(pkiMsg, idx, &length, pkiMsgSz) < 0)
12098 return ASN_PARSE_E;
12099 pbkdf2End = *idx + (word32)length;
12100
12101 /* get KDF salt OCTET STRING */
12102 if (GetASNTag(pkiMsg, idx, &tag, pkiMsgSz) < 0)
12103 return ASN_PARSE_E;
12104
12105 if (tag != ASN_OCTET_STRING)
12106 return ASN_PARSE_E;
12107
12108 if (GetLength(pkiMsg, idx, &saltSz, pkiMsgSz) < 0)
12109 return ASN_PARSE_E;
12110
12111 salt = (byte*)XMALLOC((word32)saltSz, pkcs7->heap,
12112 DYNAMIC_TYPE_PKCS7);
12113 if (salt == NULL)
12114 return MEMORY_E;
12115
12116 XMEMCPY(salt, pkiMsg + (*idx), (word32)saltSz);
12117 *idx += (word32)saltSz;
12118
12119 /* get KDF iterations */
12120 if (GetMyVersion(pkiMsg, idx, &iterations, pkiMsgSz) < 0) {
12121 XFREE(salt, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
12122 return ASN_PARSE_E;
12123 }
12124
12125 /* optional keyLength - validated below once kekKeySz is known */
12126 if (*idx < pbkdf2End && pkiMsg[*idx] == ASN_INTEGER) {
12127 if (GetShortInt(pkiMsg, idx, &keyLen, pbkdf2End) < 0) {
12128 XFREE(salt, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
12129 return ASN_PARSE_E;
12130 }
12131 keyLenPresent = 1;
12132 }
12133
12134 /* optional prf; default hmacWithSHA1 keeps hashOID at WC_SHA */
12135 if (*idx < pbkdf2End &&
12136 pkiMsg[*idx] == (ASN_SEQUENCE | ASN_CONSTRUCTED)) {
12137 word32 prfOid = 0;
12138 if (GetAlgoId(pkiMsg, idx, &prfOid, oidHmacType,
12139 pbkdf2End) < 0) {
12140 XFREE(salt, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
12141 return ASN_PARSE_E;
12142 }
12143 switch ((int)prfOid) {
12144 #ifdef WOLFSSL_SHA224
12145 case HMAC_SHA224_OID: hashOID = WC_SHA224; break;
12146 #endif
12147 #ifndef NO_SHA256
12148 case HMAC_SHA256_OID: hashOID = WC_SHA256; break;
12149 #endif
12150 #ifdef WOLFSSL_SHA384
12151 case HMAC_SHA384_OID: hashOID = WC_SHA384; break;
12152 #endif
12153 #ifdef WOLFSSL_SHA512
12154 case HMAC_SHA512_OID: hashOID = WC_SHA512; break;
12155 #endif
12156 default:
12157 /* unknown id (incl. explicit hmacWithSHA1) - keep
12158 * default WC_SHA; MAC unwrap fails if mismatched */
12159 break;
12160 }
12161 }
12162
12163 /* get KeyEncAlgoId SEQ */
12164 if (GetSequence(pkiMsg, idx, &length, pkiMsgSz) < 0) {
12165 XFREE(salt, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
12166 return ASN_PARSE_E;
12167 }
12168
12169 /* get KeyEncAlgoId */
12170 if (wc_GetContentType(pkiMsg, idx, &keyEncAlgoId, pkiMsgSz) < 0) {
12171 XFREE(salt, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
12172 return ASN_PARSE_E;
12173 }
12174
12175 /* get pwriEncAlgoId */
12176 if (GetAlgoId(pkiMsg, idx, &pwriEncAlgoId, oidBlkType,
12177 pkiMsgSz) < 0) {
12178 XFREE(salt, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
12179 return ASN_PARSE_E;
12180 }
12181
12182 blockSz = wc_PKCS7_GetOIDBlockSize((int)pwriEncAlgoId);
12183 if (blockSz < 0) {
12184 XFREE(salt, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
12185 return blockSz;
12186 }
12187
12188 /* get content-encryption key size, based on algorithm */
12189 kekKeySz = wc_PKCS7_GetOIDKeySize((int)pwriEncAlgoId);
12190 if (kekKeySz < 0) {
12191 XFREE(salt, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
12192 return kekKeySz;
12193 }
12194
12195 /* RFC 8018: when present, PBKDF2 keyLength must equal the
12196 * derived key length expected by the encryption algorithm */
12197 if (keyLenPresent && keyLen != kekKeySz) {
12198 XFREE(salt, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
12199 return ASN_PARSE_E;
12200 }
12201
12202 /* get block cipher IV, stored in OPTIONAL parameter of AlgoID */
12203 if (GetASNTag(pkiMsg, idx, &tag, pkiMsgSz) < 0) {
12204 XFREE(salt, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
12205 return ASN_PARSE_E;
12206 }
12207
12208 if (tag != ASN_OCTET_STRING) {
12209 XFREE(salt, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
12210 return ASN_PARSE_E;
12211 }
12212
12213 if (GetLength(pkiMsg, idx, &length, pkiMsgSz) < 0) {
12214 XFREE(salt, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
12215 return ASN_PARSE_E;
12216 }
12217
12218 if (length != blockSz) {
12219 WOLFSSL_MSG("Incorrect IV length, must be of content alg block "
12220 "size");
12221 XFREE(salt, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
12222 return ASN_PARSE_E;
12223 }
12224
12225 /* Validate IV is within input buffer */
12226 if (*idx > pkiMsgSz || (word32)length > pkiMsgSz - *idx) {
12227 XFREE(salt, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
12228 return ASN_PARSE_E;
12229 }
12230
12231 XMEMCPY(tmpIv, pkiMsg + (*idx), (word32)length);
12232 *idx += (word32)length;
12233
12234 /* get EncryptedKey */
12235 if (GetASNTag(pkiMsg, idx, &tag, pkiMsgSz) < 0) {
12236 XFREE(salt, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
12237 return ASN_PARSE_E;
12238 }
12239
12240 if (tag != ASN_OCTET_STRING) {
12241 XFREE(salt, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
12242 return ASN_PARSE_E;
12243 }
12244
12245 if (GetLength(pkiMsg, idx, &length, pkiMsgSz) < 0) {
12246 XFREE(salt, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
12247 return ASN_PARSE_E;
12248 }
12249
12250 /* Validate EncryptedKey is within input buffer */
12251 if (*idx > pkiMsgSz || (word32)length > pkiMsgSz - *idx) {
12252 XFREE(salt, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
12253 return ASN_PARSE_E;
12254 }
12255
12256 /* allocate temporary space for decrypted key */
12257 cekSz = (word32)length;
12258 cek = (byte*)XMALLOC(cekSz, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
12259 if (cek == NULL) {
12260 XFREE(salt, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
12261 return MEMORY_E;
12262 }
12263
12264 /* generate KEK */
12265 kek = (byte*)XMALLOC((word32)kekKeySz, pkcs7->heap,
12266 DYNAMIC_TYPE_PKCS7);
12267 if (kek == NULL) {
12268 XFREE(salt, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
12269 XFREE(cek, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
12270 return MEMORY_E;
12271 }
12272
12273 ret = wc_PKCS7_GenerateKEK_PWRI(pkcs7, pkcs7->pass, pkcs7->passSz,
12274 salt, (word32)saltSz, (int)kdfAlgoId, hashOID,
12275 iterations, kek, (word32)kekKeySz);
12276 if (ret < 0) {
12277 XFREE(salt, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
12278 ForceZero(kek, (word32)kekKeySz);
12279 XFREE(kek, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
12280 XFREE(cek, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
12281 return ASN_PARSE_E;
12282 }
12283
12284 /* decrypt CEK with KEK */
12285 ret = wc_PKCS7_PwriKek_KeyUnWrap(pkcs7, kek, (word32)kekKeySz,
12286 pkiMsg + (*idx), (word32)length,
12287 cek, cekSz, tmpIv, (word32)blockSz,
12288 pwriEncAlgoId);
12289 if (ret < 0) {
12290 XFREE(salt, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
12291 ForceZero(kek, (word32)kekKeySz);
12292 XFREE(kek, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
12293 ForceZero(cek, cekSz);
12294 XFREE(cek, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
12295 return ret;
12296 }
12297 cekSz = (word32)ret;
12298
12299 if (*decryptedKeySz < cekSz) {
12300 WOLFSSL_MSG("Decrypted key buffer too small for CEK");
12301 XFREE(salt, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
12302 ForceZero(kek, (word32)kekKeySz);
12303 XFREE(kek, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
12304 ForceZero(cek, cekSz);
12305 XFREE(cek, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
12306 return BUFFER_E;
12307 }
12308
12309 XMEMCPY(decryptedKey, cek, cekSz);
12310 *decryptedKeySz = cekSz;
12311
12312 XFREE(salt, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
12313 ForceZero(kek, (word32)kekKeySz);
12314 XFREE(kek, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
12315 ForceZero(cek, cekSz);
12316 XFREE(cek, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
12317
12318 /* mark recipFound, since we only support one RecipientInfo for now */
12319 *recipFound = 1;
12320 *idx += (word32)length;
12321 #ifndef NO_PKCS7_STREAM
12322 if ((ret = wc_PKCS7_StreamEndCase(pkcs7, &tmpIdx, idx)) != 0) {
12323 break;
12324 }
12325 #endif
12326 ret = 0; /* success */
12327 break;
12328
12329 default:
12330 WOLFSSL_MSG("PKCS7 PWRI unknown state");
12331 ret = BAD_FUNC_ARG;
12332 }
12333
12334 return ret;
12335}
12336
12337#endif /* NO_PWDBASED | NO_SHA */
12338
12339/* decode ASN.1 KEKRecipientInfo (kekri), return 0 on success,
12340 * < 0 on error */
12341static int wc_PKCS7_DecryptKekri(wc_PKCS7* pkcs7, byte* in, word32 inSz,
12342 word32* idx, byte* decryptedKey,
12343 word32* decryptedKeySz, int* recipFound)
12344{
12345 int length, keySz, dateLen, direction;
12346 byte* keyId = NULL;
12347 const byte* datePtr = NULL;
12348 byte dateFormat, tag;
12349 word32 keyIdSz, kekIdSz, kekIdEnd, keyWrapOID, localIdx;
12350
12351 int ret = 0;
12352 byte* pkiMsg = in;
12353 word32 pkiMsgSz = inSz;
12354#ifndef NO_PKCS7_STREAM
12355 word32 tmpIdx = *idx;
12356#endif
12357
12358 WOLFSSL_ENTER("wc_PKCS7_DecryptKekri");
12359 switch (pkcs7->state) {
12360 case WC_PKCS7_DECRYPT_KEKRI:
12361 #ifndef NO_PKCS7_STREAM
12362 /* @TODO for now just get full buffer, needs divided up */
12363 if ((ret = wc_PKCS7_AddDataToStream(pkcs7, in, inSz,
12364 (pkcs7->stream->maxLen - pkcs7->stream->totalRd) +
12365 pkcs7->stream->length, &pkiMsg, idx)) != 0) {
12366 return ret;
12367 }
12368 pkiMsgSz = (pkcs7->stream->length > 0)? pkcs7->stream->length: inSz;
12369 #endif
12370 /* remove KEKIdentifier */
12371 if (GetSequence(pkiMsg, idx, &length, pkiMsgSz) < 0)
12372 return ASN_PARSE_E;
12373
12374 kekIdSz = (word32)length;
12375 kekIdEnd = *idx + kekIdSz;
12376
12377 /* Validate KEKIdentifier boundary is within input buffer */
12378 if (kekIdEnd < *idx || kekIdEnd > pkiMsgSz)
12379 return ASN_PARSE_E;
12380
12381 if (GetASNTag(pkiMsg, idx, &tag, pkiMsgSz) < 0)
12382 return ASN_PARSE_E;
12383
12384 if (tag != ASN_OCTET_STRING)
12385 return ASN_PARSE_E;
12386
12387 if (GetLength(pkiMsg, idx, &length, pkiMsgSz) < 0)
12388 return ASN_PARSE_E;
12389
12390 /* Validate keyIdentifier is within input buffer */
12391 if (*idx > pkiMsgSz || (word32)length > pkiMsgSz - *idx)
12392 return ASN_PARSE_E;
12393
12394 /* save keyIdentifier and length */
12395 keyId = pkiMsg + *idx;
12396 keyIdSz = (word32)length;
12397 *idx += keyIdSz;
12398
12399 /* may have OPTIONAL GeneralizedTime */
12400 localIdx = *idx;
12401 if ((*idx < kekIdEnd) && GetASNTag(pkiMsg, &localIdx, &tag,
12402 pkiMsgSz) == 0 && tag == ASN_GENERALIZED_TIME) {
12403 if (wc_GetDateInfo(pkiMsg + *idx, (int)(pkiMsgSz - *idx),
12404 &datePtr, &dateFormat, &dateLen) != 0) {
12405 return ASN_PARSE_E;
12406 }
12407 /* datePtr points to the start of the date value
12408 * within pkiMsg; advance past the full TLV. */
12409 *idx = (word32)(datePtr - pkiMsg) + (word32)dateLen;
12410 }
12411
12412 if (*idx > pkiMsgSz) {
12413 return ASN_PARSE_E;
12414 }
12415
12416 /* may have OPTIONAL OtherKeyAttribute */
12417 localIdx = *idx;
12418 if ((*idx < kekIdEnd) && GetASNTag(pkiMsg, &localIdx, &tag,
12419 pkiMsgSz) == 0 && tag == (ASN_SEQUENCE |
12420 ASN_CONSTRUCTED)) {
12421 if (GetSequence(pkiMsg, idx, &length, pkiMsgSz) < 0)
12422 return ASN_PARSE_E;
12423
12424 /* skip it */
12425 *idx += (word32)length;
12426 }
12427
12428 if (*idx > pkiMsgSz) {
12429 return ASN_PARSE_E;
12430 }
12431
12432 /* get KeyEncryptionAlgorithmIdentifier */
12433 if (GetAlgoId(pkiMsg, idx, &keyWrapOID, oidKeyWrapType, pkiMsgSz)
12434 < 0)
12435 return ASN_PARSE_E;
12436
12437 /* get EncryptedKey */
12438 if (GetASNTag(pkiMsg, idx, &tag, pkiMsgSz) < 0)
12439 return ASN_PARSE_E;
12440
12441 if (tag != ASN_OCTET_STRING)
12442 return ASN_PARSE_E;
12443
12444 if (GetLength(pkiMsg, idx, &length, pkiMsgSz) < 0)
12445 return ASN_PARSE_E;
12446
12447 /* Validate EncryptedKey is within input buffer */
12448 if (*idx > pkiMsgSz || (word32)length > pkiMsgSz - *idx)
12449 return ASN_PARSE_E;
12450
12451 #ifndef NO_AES
12452 direction = AES_DECRYPTION;
12453 #else
12454 direction = DES_DECRYPTION;
12455 #endif
12456
12457 /* decrypt CEK with KEK */
12458 if (pkcs7->wrapCEKCb) {
12459 keySz = pkcs7->wrapCEKCb(pkcs7, pkiMsg + *idx, (word32)length,
12460 keyId, keyIdSz, NULL, 0, decryptedKey,
12461 *decryptedKeySz, (int)keyWrapOID,
12462 (int)PKCS7_KEKRI, direction);
12463 }
12464 else {
12465 keySz = wc_PKCS7_KeyWrap(pkcs7, pkiMsg + *idx, (word32)length,
12466 pkcs7->privateKey, pkcs7->privateKeySz, decryptedKey,
12467 *decryptedKeySz, (int)keyWrapOID, direction);
12468 }
12469 if (keySz <= 0)
12470 return keySz;
12471
12472 *decryptedKeySz = (word32)keySz;
12473
12474 /* mark recipFound, since we only support one RecipientInfo for
12475 * now */
12476 *recipFound = 1;
12477 *idx += (word32)length;
12478
12479 #ifndef NO_PKCS7_STREAM
12480 if ((ret = wc_PKCS7_StreamEndCase(pkcs7, &tmpIdx, idx)) != 0) {
12481 break;
12482 }
12483 #endif
12484 ret = 0; /* success */
12485 break;
12486
12487 default:
12488 WOLFSSL_MSG("PKCS7 KEKRI unknown state");
12489 ret = BAD_FUNC_ARG;
12490
12491 }
12492
12493 (void)keyId;
12494 return ret;
12495}
12496
12497
12498/* decode ASN.1 KeyAgreeRecipientInfo (kari), return 0 on success,
12499 * < 0 on error */
12500static int wc_PKCS7_DecryptKari(wc_PKCS7* pkcs7, byte* in, word32 inSz,
12501 word32* idx, byte* decryptedKey,
12502 word32* decryptedKeySz, int* recipFound)
12503{
12504#ifdef HAVE_ECC
12505 int ret, keySz;
12506 int encryptedKeySz;
12507 int direction = 0;
12508 int keyIdSize;
12509 word32 keyAgreeOID, keyWrapOID;
12510 byte rid[KEYID_SIZE];
12511
12512 WC_DECLARE_VAR(encryptedKey, byte, MAX_ENCRYPTED_KEY_SZ, 0);
12513
12514 byte* pkiMsg = in;
12515 word32 pkiMsgSz = inSz;
12516#ifndef NO_PKCS7_STREAM
12517 word32 tmpIdx = (idx) ? *idx : 0;
12518#endif
12519 WOLFSSL_ENTER("wc_PKCS7_DecryptKari");
12520 if (pkcs7 == NULL || pkiMsg == NULL ||
12521 idx == NULL || decryptedKey == NULL || decryptedKeySz == NULL) {
12522 return BAD_FUNC_ARG;
12523 }
12524
12525#if defined(WOLFSSL_SM2) && defined(WOLFSSL_SM3)
12526 keyIdSize = wc_HashGetDigestSize(wc_HashTypeConvert(HashIdAlg(
12527 pkcs7->publicKeyOID)));
12528#else
12529 keyIdSize = KEYID_SIZE;
12530#endif
12531
12532 switch (pkcs7->state) {
12533 case WC_PKCS7_DECRYPT_KARI: {
12534 WC_PKCS7_KARI* kari;
12535
12536 #ifndef NO_PKCS7_STREAM
12537 /* @TODO for now just get full buffer, needs divided up */
12538 if ((ret = wc_PKCS7_AddDataToStream(pkcs7, in, inSz,
12539 (pkcs7->stream->maxLen - pkcs7->stream->totalRd) +
12540 pkcs7->stream->length, &pkiMsg, idx)) != 0) {
12541 return ret;
12542 }
12543 pkiMsgSz = (pkcs7->stream->length > 0)? pkcs7->stream->length: inSz;
12544 #endif
12545
12546 kari = wc_PKCS7_KariNew(pkcs7, WC_PKCS7_DECODE);
12547 if (kari == NULL)
12548 return MEMORY_E;
12549
12550 WC_ALLOC_VAR_EX(encryptedKey, byte, MAX_ENCRYPTED_KEY_SZ,
12551 pkcs7->heap, DYNAMIC_TYPE_PKCS7,
12552 {
12553 wc_PKCS7_KariFree(kari);
12554 return MEMORY_E;
12555 });
12556 encryptedKeySz = MAX_ENCRYPTED_KEY_SZ;
12557
12558 /* parse cert and key */
12559 ret = wc_PKCS7_KariParseRecipCert(kari, (byte*)pkcs7->singleCert,
12560 pkcs7->singleCertSz, pkcs7->privateKey,
12561 pkcs7->privateKeySz);
12562
12563 if (ret != 0) {
12564 wc_PKCS7_KariFree(kari);
12565 WC_FREE_VAR_EX(encryptedKey, pkcs7->heap,
12566 DYNAMIC_TYPE_PKCS7);
12567 return ret;
12568 }
12569
12570 /* remove OriginatorIdentifierOrKey */
12571 ret = wc_PKCS7_KariGetOriginatorIdentifierOrKey(kari, pkiMsg,
12572 pkiMsgSz, idx);
12573 if (ret != 0) {
12574 wc_PKCS7_KariFree(kari);
12575 WC_FREE_VAR_EX(encryptedKey, pkcs7->heap,
12576 DYNAMIC_TYPE_PKCS7);
12577 return ret;
12578 }
12579
12580 /* try and remove optional UserKeyingMaterial */
12581 ret = wc_PKCS7_KariGetUserKeyingMaterial(kari, pkiMsg, pkiMsgSz,
12582 idx);
12583 if (ret != 0) {
12584 wc_PKCS7_KariFree(kari);
12585 WC_FREE_VAR_EX(encryptedKey, pkcs7->heap,
12586 DYNAMIC_TYPE_PKCS7);
12587 return ret;
12588 }
12589
12590 /* remove KeyEncryptionAlgorithmIdentifier */
12591 ret = wc_PKCS7_KariGetKeyEncryptionAlgorithmId(kari, pkiMsg,
12592 pkiMsgSz, idx, &keyAgreeOID, &keyWrapOID);
12593 if (ret != 0) {
12594 wc_PKCS7_KariFree(kari);
12595 WC_FREE_VAR_EX(encryptedKey, pkcs7->heap,
12596 DYNAMIC_TYPE_PKCS7);
12597 return ret;
12598 }
12599
12600 /* if user has not explicitly set keyAgreeOID, set from one in
12601 * bundle */
12602 if (pkcs7->keyAgreeOID == 0)
12603 pkcs7->keyAgreeOID = (int)keyAgreeOID;
12604
12605 /* set direction based on key wrap algorithm */
12606 switch (keyWrapOID) {
12607 #ifndef NO_AES
12608 #ifdef WOLFSSL_AES_128
12609 case AES128_WRAP:
12610 #endif
12611 #ifdef WOLFSSL_AES_192
12612 case AES192_WRAP:
12613 #endif
12614 #ifdef WOLFSSL_AES_256
12615 case AES256_WRAP:
12616 #endif
12617 direction = AES_DECRYPTION;
12618 break;
12619 #endif
12620 default:
12621 WOLFSSL_MSG("AES key wrap algorithm unsupported");
12622 if (pkcs7->wrapCEKCb) {
12623 WOLFSSL_MSG("Direction not set!");
12624 break; /* if unwrapping callback is set then do not
12625 * force restriction of supported wrap
12626 * algorithms */
12627 }
12628
12629 wc_PKCS7_KariFree(kari);
12630 WC_FREE_VAR_EX(encryptedKey, pkcs7->heap,
12631 DYNAMIC_TYPE_PKCS7);
12632 return BAD_KEYWRAP_ALG_E;
12633 }
12634
12635 /* remove RecipientEncryptedKeys */
12636 ret = wc_PKCS7_KariGetRecipientEncryptedKeys(kari, pkiMsg, pkiMsgSz,
12637 idx, recipFound, encryptedKey, &encryptedKeySz, rid);
12638 if (ret != 0) {
12639 wc_PKCS7_KariFree(kari);
12640 WC_FREE_VAR_EX(encryptedKey, pkcs7->heap,
12641 DYNAMIC_TYPE_PKCS7);
12642 return ret;
12643 }
12644
12645 /* decrypt CEK with KEK */
12646 if (pkcs7->wrapCEKCb) {
12647 word32 tmpKeySz = 0;
12648 byte* tmpKeyDer = NULL;
12649
12650 PRIVATE_KEY_UNLOCK();
12651 ret = wc_ecc_export_x963(kari->senderKey, NULL, &tmpKeySz);
12652 PRIVATE_KEY_LOCK();
12653 if (ret != WC_NO_ERR_TRACE(LENGTH_ONLY_E)) {
12654 wc_PKCS7_KariFree(kari);
12655 WC_FREE_VAR_EX(encryptedKey, pkcs7->heap,
12656 DYNAMIC_TYPE_PKCS7);
12657 return ret;
12658 }
12659
12660 /* buffer space for algorithm/curve */
12661 tmpKeySz += MAX_SEQ_SZ;
12662 tmpKeySz += 2 * MAX_ALGO_SZ;
12663
12664 /* buffer space for public key sequence */
12665 tmpKeySz += MAX_SEQ_SZ;
12666 tmpKeySz += TRAILING_ZERO;
12667
12668 tmpKeyDer = (byte*)XMALLOC(tmpKeySz, pkcs7->heap,
12669 DYNAMIC_TYPE_TMP_BUFFER);
12670 if (tmpKeyDer == NULL) {
12671 wc_PKCS7_KariFree(kari);
12672 WC_FREE_VAR_EX(encryptedKey, pkcs7->heap,
12673 DYNAMIC_TYPE_PKCS7);
12674 return MEMORY_E;
12675 }
12676
12677 ret = wc_EccPublicKeyToDer(kari->senderKey, tmpKeyDer,
12678 tmpKeySz, 1);
12679 if (ret < 0) {
12680 wc_PKCS7_KariFree(kari);
12681 WC_FREE_VAR_EX(encryptedKey, pkcs7->heap,
12682 DYNAMIC_TYPE_PKCS7);
12683 XFREE(tmpKeyDer, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
12684 return ret;
12685 }
12686 tmpKeySz = (word32)ret;
12687
12688 keySz = pkcs7->wrapCEKCb(pkcs7, encryptedKey,
12689 (word32)encryptedKeySz, rid, (word32)keyIdSize, tmpKeyDer,
12690 tmpKeySz, decryptedKey, *decryptedKeySz,
12691 (int)keyWrapOID, (int)PKCS7_KARI, direction);
12692 XFREE(tmpKeyDer, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
12693
12694 if (keySz > 0) {
12695 /* If unwrapping was successful then consider recipient
12696 * found. Checking for NULL singleCert to confirm previous
12697 * SID check was not done */
12698 if (pkcs7->singleCert == NULL)
12699 *recipFound = 1;
12700 }
12701 }
12702 else {
12703 /* create KEK */
12704 ret = wc_PKCS7_KariGenerateKEK(kari, pkcs7->rng,
12705 (int)keyWrapOID, pkcs7->keyAgreeOID);
12706 if (ret != 0) {
12707 wc_PKCS7_KariFree(kari);
12708 WC_FREE_VAR_EX(encryptedKey, pkcs7->heap,
12709 DYNAMIC_TYPE_PKCS7);
12710 return ret;
12711 }
12712
12713 /* decrypt CEK with KEK */
12714 keySz = wc_PKCS7_KeyWrap(pkcs7, encryptedKey,
12715 (word32)encryptedKeySz, kari->kek, kari->kekSz,
12716 decryptedKey, *decryptedKeySz, (int)keyWrapOID,
12717 direction);
12718 }
12719 if (keySz <= 0) {
12720 wc_PKCS7_KariFree(kari);
12721 WC_FREE_VAR_EX(encryptedKey, pkcs7->heap,
12722 DYNAMIC_TYPE_PKCS7);
12723 return keySz;
12724 }
12725 *decryptedKeySz = (word32)keySz;
12726
12727 wc_PKCS7_KariFree(kari);
12728 WC_FREE_VAR_EX(encryptedKey, pkcs7->heap,
12729 DYNAMIC_TYPE_PKCS7);
12730 #ifndef NO_PKCS7_STREAM
12731 if ((ret = wc_PKCS7_StreamEndCase(pkcs7, &tmpIdx, idx)) != 0) {
12732 break;
12733 }
12734 #endif
12735 ret = 0; /* success */
12736 }
12737 break;
12738
12739 default:
12740 WOLFSSL_MSG("PKCS7 kari unknown state");
12741 ret = BAD_FUNC_ARG;
12742
12743 }
12744
12745 (void)pkiMsg;
12746 (void)pkiMsgSz;
12747
12748 return ret;
12749#else
12750 (void)in;
12751 (void)inSz;
12752 (void)pkcs7;
12753 (void)idx;
12754 (void)decryptedKey;
12755 (void)decryptedKeySz;
12756 (void)recipFound;
12757
12758 return NOT_COMPILED_IN;
12759#endif /* HAVE_ECC */
12760}
12761
12762
12763/* decode ASN.1 RecipientInfos SET, return 0 on success, < 0 on error */
12764static int wc_PKCS7_DecryptRecipientInfos(wc_PKCS7* pkcs7, byte* in,
12765 word32 inSz, word32* idx, byte* decryptedKey,
12766 word32* decryptedKeySz, int* recipFound)
12767{
12768 word32 savedIdx;
12769 int version, ret = 0, length;
12770 byte* pkiMsg = in;
12771 word32 pkiMsgSz = inSz;
12772 byte tag;
12773#ifndef NO_PKCS7_STREAM
12774 word32 tmpIdx;
12775#endif
12776
12777 if (pkcs7 == NULL || pkiMsg == NULL || idx == NULL ||
12778 decryptedKey == NULL || decryptedKeySz == NULL ||
12779 recipFound == NULL) {
12780 return BAD_FUNC_ARG;
12781 }
12782
12783 WOLFSSL_ENTER("wc_PKCS7_DecryptRecipientInfos");
12784#ifndef NO_PKCS7_STREAM
12785 tmpIdx = *idx;
12786#endif
12787
12788 /* check if in the process of decrypting */
12789 switch (pkcs7->state) {
12790 case WC_PKCS7_DECRYPT_KTRI:
12791 case WC_PKCS7_DECRYPT_KTRI_2:
12792 case WC_PKCS7_DECRYPT_KTRI_3:
12793 #ifndef NO_RSA
12794 ret = wc_PKCS7_DecryptKtri(pkcs7, in, inSz, idx,
12795 decryptedKey, decryptedKeySz, recipFound);
12796 #else
12797 return NOT_COMPILED_IN;
12798 #endif
12799 break;
12800
12801 case WC_PKCS7_DECRYPT_KARI:
12802 ret = wc_PKCS7_DecryptKari(pkcs7, in, inSz, idx,
12803 decryptedKey, decryptedKeySz, recipFound);
12804 break;
12805
12806 case WC_PKCS7_DECRYPT_KEKRI:
12807 ret = wc_PKCS7_DecryptKekri(pkcs7, in, inSz, idx,
12808 decryptedKey, decryptedKeySz, recipFound);
12809 break;
12810
12811 case WC_PKCS7_DECRYPT_PWRI:
12812 #if !defined(NO_PWDBASED) && !defined(NO_SHA)
12813 ret = wc_PKCS7_DecryptPwri(pkcs7, in, inSz, idx,
12814 decryptedKey, decryptedKeySz, recipFound);
12815 break;
12816 #else
12817 return NOT_COMPILED_IN;
12818 #endif
12819
12820 case WC_PKCS7_DECRYPT_ORI:
12821 ret = wc_PKCS7_DecryptOri(pkcs7, in, inSz, idx,
12822 decryptedKey, decryptedKeySz, recipFound);
12823 break;
12824
12825 default:
12826 /* not in decrypting state */
12827 break;
12828 }
12829
12830 if (ret < 0) {
12831 return ret;
12832 }
12833
12834 savedIdx = *idx;
12835#ifndef NO_PKCS7_STREAM
12836 pkiMsgSz = (pkcs7->stream->length > 0)? pkcs7->stream->length: inSz;
12837 if (pkcs7->stream->length > 0)
12838 pkiMsg = pkcs7->stream->buffer;
12839#endif
12840
12841 /* when looking for next recipient, use first sequence and version to
12842 * indicate there is another, if not, move on */
12843 while (*recipFound == 0) {
12844
12845 /* remove RecipientInfo, if we don't have a SEQUENCE, back up idx to
12846 * last good saved one */
12847 if (GetSequence_ex(pkiMsg, idx, &length, pkiMsgSz, NO_USER_CHECK) > 0) {
12848
12849 #ifndef NO_RSA
12850 /* found ktri */
12851 #ifndef NO_PKCS7_STREAM
12852 if ((ret = wc_PKCS7_StreamEndCase(pkcs7, &tmpIdx, idx)) != 0) {
12853 break;
12854 }
12855 #endif
12856 wc_PKCS7_ChangeState(pkcs7, WC_PKCS7_DECRYPT_KTRI);
12857 ret = wc_PKCS7_DecryptKtri(pkcs7, in, inSz, idx,
12858 decryptedKey, decryptedKeySz,
12859 recipFound);
12860 if (ret != 0) {
12861 if (ret != WC_NO_ERR_TRACE(WC_PKCS7_WANT_READ_E) &&
12862 *recipFound == 0) {
12863 continue; /* try next recipient */
12864 }
12865 else {
12866 return ret; /* found recipient and failed decrypt */
12867 }
12868 }
12869 #else
12870 return NOT_COMPILED_IN;
12871 #endif
12872 }
12873 else {
12874 word32 localIdx;
12875 /* kari is IMPLICIT[1] */
12876 *idx = savedIdx;
12877 localIdx = *idx;
12878
12879 if (GetASNTag(pkiMsg, &localIdx, &tag, pkiMsgSz) != 0) {
12880 /* no room for recipient info */
12881 break;
12882 }
12883
12884 if (tag == (ASN_CONSTRUCTED | ASN_CONTEXT_SPECIFIC | 1)) {
12885 (*idx)++;
12886 if (GetLength_ex(pkiMsg, idx, &length, pkiMsgSz,
12887 NO_USER_CHECK) < 0)
12888 return ASN_PARSE_E;
12889
12890 if (GetMyVersion(pkiMsg, idx, &version, pkiMsgSz) < 0) {
12891 *idx = savedIdx;
12892 break;
12893 }
12894
12895 if (version != 3)
12896 return ASN_VERSION_E;
12897
12898 /* found kari */
12899 #ifndef NO_PKCS7_STREAM
12900 if ((ret = wc_PKCS7_StreamEndCase(pkcs7, &tmpIdx, idx)) != 0) {
12901 break;
12902 }
12903 #endif
12904 wc_PKCS7_ChangeState(pkcs7, WC_PKCS7_DECRYPT_KARI);
12905 ret = wc_PKCS7_DecryptKari(pkcs7, in, inSz, idx,
12906 decryptedKey, decryptedKeySz,
12907 recipFound);
12908 if (ret != 0)
12909 return ret;
12910
12911 /* kekri is IMPLICIT[2] */
12912 } else if (tag == (ASN_CONSTRUCTED | ASN_CONTEXT_SPECIFIC | 2)) {
12913 (*idx)++;
12914
12915 if (GetLength_ex(pkiMsg, idx, &version, pkiMsgSz,
12916 NO_USER_CHECK) < 0)
12917 return ASN_PARSE_E;
12918
12919 if (GetMyVersion(pkiMsg, idx, &version, pkiMsgSz) < 0) {
12920 *idx = savedIdx;
12921 break;
12922 }
12923
12924 if (version != 4)
12925 return ASN_VERSION_E;
12926
12927 /* found kekri */
12928 #ifndef NO_PKCS7_STREAM
12929 if ((ret = wc_PKCS7_StreamEndCase(pkcs7, &tmpIdx, idx)) != 0) {
12930 break;
12931 }
12932 #endif
12933 wc_PKCS7_ChangeState(pkcs7, WC_PKCS7_DECRYPT_KEKRI);
12934 ret = wc_PKCS7_DecryptKekri(pkcs7, in, inSz, idx,
12935 decryptedKey, decryptedKeySz,
12936 recipFound);
12937 if (ret != 0)
12938 return ret;
12939
12940 /* pwri is IMPLICIT[3] */
12941 } else if (tag == (ASN_CONSTRUCTED | ASN_CONTEXT_SPECIFIC | 3)) {
12942 #if !defined(NO_PWDBASED) && !defined(NO_SHA)
12943 (*idx)++;
12944
12945 if (GetLength_ex(pkiMsg, idx, &version, pkiMsgSz,
12946 NO_USER_CHECK) < 0)
12947 return ASN_PARSE_E;
12948
12949 if (GetMyVersion(pkiMsg, idx, &version, pkiMsgSz) < 0) {
12950 *idx = savedIdx;
12951 break;
12952 }
12953
12954 if (version != 0)
12955 return ASN_VERSION_E;
12956
12957 /* found pwri */
12958 #ifndef NO_PKCS7_STREAM
12959 if ((ret = wc_PKCS7_StreamEndCase(pkcs7, &tmpIdx, idx)) != 0) {
12960 break;
12961 }
12962 #endif
12963 wc_PKCS7_ChangeState(pkcs7, WC_PKCS7_DECRYPT_PWRI);
12964 ret = wc_PKCS7_DecryptPwri(pkcs7, in, inSz, idx,
12965 decryptedKey, decryptedKeySz,
12966 recipFound);
12967 if (ret != 0)
12968 return ret;
12969 #else
12970 return NOT_COMPILED_IN;
12971 #endif
12972
12973 /* ori is IMPLICIT[4] */
12974 } else if (tag == (ASN_CONSTRUCTED | ASN_CONTEXT_SPECIFIC | 4)) {
12975 (*idx)++;
12976
12977 /* found ori */
12978 #ifndef NO_PKCS7_STREAM
12979 if ((ret = wc_PKCS7_StreamEndCase(pkcs7, &tmpIdx, idx)) != 0) {
12980 break;
12981 }
12982 #endif
12983 wc_PKCS7_ChangeState(pkcs7, WC_PKCS7_DECRYPT_ORI);
12984 ret = wc_PKCS7_DecryptOri(pkcs7, in, inSz, idx,
12985 decryptedKey, decryptedKeySz,
12986 recipFound);
12987 if (ret != 0)
12988 return ret;
12989 }
12990 else {
12991 /* failed to find RecipientInfo, restore idx and continue */
12992 *idx = savedIdx;
12993 break;
12994 }
12995 }
12996
12997 /* update good idx */
12998 savedIdx = *idx;
12999 }
13000
13001 return ret;
13002}
13003
13004
13005/* Parse encoded EnvelopedData bundle up to RecipientInfo set.
13006 *
13007 * return size of RecipientInfo SET on success, negative upon error */
13008static int wc_PKCS7_ParseToRecipientInfoSet(wc_PKCS7* pkcs7, byte* in,
13009 word32 inSz, word32* idx,
13010 int type)
13011{
13012 int version = 0, length = 0, ret = 0;
13013 word32 contentType= 0;
13014 word32 pkiMsgSz = inSz;
13015 byte* pkiMsg = in;
13016 byte tag = 0;
13017#ifndef NO_PKCS7_STREAM
13018 word32 tmpIdx = 0;
13019#endif
13020
13021 if (pkcs7 == NULL || pkiMsg == NULL || pkiMsgSz == 0 || idx == NULL)
13022 return BAD_FUNC_ARG;
13023
13024 if ((type != ENVELOPED_DATA) && (type != AUTH_ENVELOPED_DATA) &&
13025 pkcs7->contentOID != FIRMWARE_PKG_DATA
13026 #if defined(HAVE_LIBZ) && !defined(NO_PKCS7_COMPRESSED_DATA)
13027 && pkcs7->contentOID != COMPRESSED_DATA
13028 #endif
13029 )
13030 return BAD_FUNC_ARG;
13031
13032#ifndef NO_PKCS7_STREAM
13033 if (pkcs7->stream == NULL) {
13034 if ((ret = wc_PKCS7_CreateStream(pkcs7)) != 0) {
13035 return ret;
13036 }
13037 }
13038#endif
13039
13040 switch (pkcs7->state) {
13041 case WC_PKCS7_INFOSET_START:
13042 case WC_PKCS7_INFOSET_STAGE1:
13043 case WC_PKCS7_INFOSET_STAGE2:
13044 case WC_PKCS7_INFOSET_END:
13045 break;
13046
13047 default:
13048 WOLFSSL_MSG("Warning, setting PKCS7 info state to start");
13049 wc_PKCS7_ChangeState(pkcs7, WC_PKCS7_INFOSET_START);
13050 }
13051
13052 switch (pkcs7->state) {
13053 case WC_PKCS7_INFOSET_START:
13054 #ifndef NO_PKCS7_STREAM
13055 if ((ret = wc_PKCS7_AddDataToStream(pkcs7, in, inSz, MAX_SEQ_SZ +
13056 ASN_TAG_SZ, &pkiMsg, idx)) != 0) {
13057 return ret;
13058 }
13059 if ((ret = wc_PKCS7_SetMaxStream(pkcs7, in, inSz)) != 0) {
13060 break;
13061 }
13062 pkiMsgSz = (pkcs7->stream->length > 0)? pkcs7->stream->length: inSz;
13063 #endif
13064 /* read past ContentInfo, verify type is envelopedData */
13065 if (ret == 0 && GetSequence_ex(pkiMsg, idx, &length, pkiMsgSz,
13066 NO_USER_CHECK) < 0)
13067 {
13068 ret = ASN_PARSE_E;
13069 }
13070
13071 if (ret == 0 && length == 0 && pkiMsg[(*idx)-1] == 0x80) {
13072 #ifdef ASN_BER_TO_DER
13073 pkcs7->indefDepth++;
13074 #else
13075 return BER_INDEF_E;
13076 #endif
13077 }
13078 #ifndef NO_PKCS7_STREAM
13079 if ((ret = wc_PKCS7_StreamEndCase(pkcs7, &tmpIdx, idx)) != 0) {
13080 break;
13081 }
13082 #endif
13083 wc_PKCS7_ChangeState(pkcs7, WC_PKCS7_INFOSET_STAGE1);
13084 FALL_THROUGH;
13085
13086 case WC_PKCS7_INFOSET_STAGE1:
13087 #ifndef NO_PKCS7_STREAM
13088 if ((ret = wc_PKCS7_AddDataToStream(pkcs7, in, inSz, MAX_OID_SZ +
13089 MAX_LENGTH_SZ + ASN_TAG_SZ, &pkiMsg, idx)) != 0) {
13090 return ret;
13091 }
13092
13093 pkiMsgSz = (pkcs7->stream->length > 0)? pkcs7->stream->length :inSz;
13094 #endif
13095 if (pkcs7->contentOID != FIRMWARE_PKG_DATA ||
13096 type == AUTH_ENVELOPED_DATA) {
13097 if (ret == 0 && wc_GetContentType(pkiMsg, idx, &contentType,
13098 pkiMsgSz) < 0)
13099 ret = ASN_PARSE_E;
13100
13101 if (ret == 0) {
13102 if (type == ENVELOPED_DATA && contentType !=
13103 ENVELOPED_DATA) {
13104 WOLFSSL_MSG("PKCS#7 input not of type EnvelopedData");
13105 ret = PKCS7_OID_E;
13106 } else if (type == AUTH_ENVELOPED_DATA &&
13107 contentType != AUTH_ENVELOPED_DATA) {
13108 WOLFSSL_MSG("PKCS#7 input not of type AuthEnvelopedData");
13109 ret = PKCS7_OID_E;
13110 }
13111 }
13112
13113 if (ret == 0 && GetASNTag(pkiMsg, idx, &tag, pkiMsgSz) != 0)
13114 ret = ASN_PARSE_E;
13115
13116 if (ret == 0 && tag != (ASN_CONSTRUCTED | ASN_CONTEXT_SPECIFIC
13117 | 0))
13118 ret = ASN_PARSE_E;
13119
13120 if (ret == 0 && GetLength_ex(pkiMsg, idx, &length, pkiMsgSz,
13121 NO_USER_CHECK) < 0)
13122 ret = ASN_PARSE_E;
13123 }
13124
13125 if (ret < 0)
13126 break;
13127
13128 #ifndef NO_PKCS7_STREAM
13129 if ((ret = wc_PKCS7_StreamEndCase(pkcs7, &tmpIdx, idx)) != 0) {
13130 break;
13131 }
13132 #endif
13133 wc_PKCS7_ChangeState(pkcs7, WC_PKCS7_INFOSET_STAGE2);
13134 FALL_THROUGH;
13135
13136 case WC_PKCS7_INFOSET_STAGE2:
13137 #ifndef NO_PKCS7_STREAM
13138 if ((ret = wc_PKCS7_AddDataToStream(pkcs7, in, inSz, MAX_SEQ_SZ +
13139 MAX_VERSION_SZ, &pkiMsg, idx)) != 0) {
13140 return ret;
13141 }
13142 pkiMsgSz = (pkcs7->stream->length > 0)? pkcs7->stream->length: inSz;
13143 #endif
13144 /* remove EnvelopedData and version */
13145 if (pkcs7->contentOID != FIRMWARE_PKG_DATA ||
13146 type == AUTH_ENVELOPED_DATA) {
13147 if (ret == 0 && GetSequence_ex(pkiMsg, idx, &length, pkiMsgSz,
13148 NO_USER_CHECK) < 0)
13149 ret = ASN_PARSE_E;
13150 }
13151
13152 if (ret == 0 && GetMyVersion(pkiMsg, idx, &version, pkiMsgSz) < 0)
13153 ret = ASN_PARSE_E;
13154
13155 if (ret < 0)
13156 break;
13157
13158 #ifndef NO_PKCS7_STREAM
13159 if ((ret = wc_PKCS7_StreamEndCase(pkcs7, &tmpIdx, idx)) != 0) {
13160 break;
13161 }
13162
13163 pkcs7->stream->varOne = (word32)version;
13164 #endif
13165 wc_PKCS7_ChangeState(pkcs7, WC_PKCS7_INFOSET_END);
13166 FALL_THROUGH;
13167
13168 case WC_PKCS7_INFOSET_END:
13169 #ifndef NO_PKCS7_STREAM
13170 if ((ret = wc_PKCS7_AddDataToStream(pkcs7, in, inSz,
13171 MAX_SET_SZ, &pkiMsg, idx)) != 0) {
13172 return ret;
13173 }
13174 pkiMsgSz = (pkcs7->stream->length > 0)? pkcs7->stream->length: inSz;
13175 version = (int)pkcs7->stream->varOne;
13176 #endif
13177
13178 if (type == ENVELOPED_DATA) {
13179 /* TODO :: make this more accurate */
13180 if ((pkcs7->publicKeyOID == RSAk &&
13181 (version != 0 && version != 2))
13182 #ifdef HAVE_ECC
13183 || (pkcs7->publicKeyOID == ECDSAk &&
13184 (version != 0 && version != 2 && version != 3))
13185 #endif
13186 ) {
13187 WOLFSSL_MSG("PKCS#7 envelopedData version incorrect");
13188 ret = ASN_VERSION_E;
13189 }
13190 } else {
13191 /* AuthEnvelopedData version MUST be 0 */
13192 if (version != 0) {
13193 WOLFSSL_MSG(
13194 "PKCS#7 AuthEnvelopedData needs to be of version 0");
13195 ret = ASN_VERSION_E;
13196 }
13197 }
13198
13199 /* remove RecipientInfo set, get length of set */
13200 if (ret == 0 && GetSet_ex(pkiMsg, idx, &length, pkiMsgSz,
13201 NO_USER_CHECK) < 0)
13202 ret = ASN_PARSE_E;
13203
13204 /* GetSet_ex is called with NO_USER_CHECK, which skips the
13205 * (idx + length > maxIdx) bounds check in GetLength_ex. In
13206 * non-streaming mode, validate the SET length against the
13207 * remaining input buffer; in streaming mode the length flows
13208 * into pkcs7->stream->expected and then wc_PKCS7_GrowStream,
13209 * where it is capped by WOLFSSL_PKCS7_MAX_STREAM_ALLOC. */
13210 if (ret == 0 && length < 0)
13211 ret = ASN_PARSE_E;
13212 #ifdef NO_PKCS7_STREAM
13213 if (ret == 0 &&
13214 (*idx > pkiMsgSz ||
13215 (word32)length > pkiMsgSz - *idx)) {
13216 ret = ASN_PARSE_E;
13217 }
13218 #endif
13219
13220 if (ret < 0)
13221 break;
13222
13223 #ifndef NO_PKCS7_STREAM
13224 pkcs7->stream->expected = (word32)length;
13225
13226 if ((ret = wc_PKCS7_StreamEndCase(pkcs7, &tmpIdx, idx)) != 0) {
13227 break;
13228 }
13229
13230 /* update the stored max length */
13231 if (pkcs7->stream->totalRd + pkcs7->stream->expected >
13232 pkcs7->stream->maxLen) {
13233 pkcs7->stream->maxLen = pkcs7->stream->totalRd +
13234 pkcs7->stream->expected;
13235 }
13236 #endif
13237
13238 if (ret == 0)
13239 ret = length;
13240
13241 break;
13242
13243 default:
13244 WOLFSSL_MSG("Bad PKCS7 info set state");
13245 ret = BAD_FUNC_ARG;
13246 break;
13247 }
13248
13249 return ret;
13250}
13251
13252
13253/* Import secret/private key into a PKCS7 structure. Used for setting
13254 * the secret key for decryption a EnvelopedData KEKRI RecipientInfo.
13255 *
13256 * Returns 0 on success, negative upon error */
13257int wc_PKCS7_SetKey(wc_PKCS7* pkcs7, byte* key, word32 keySz)
13258{
13259 if (pkcs7 == NULL || key == NULL || keySz == 0)
13260 return BAD_FUNC_ARG;
13261
13262 pkcs7->privateKey = key;
13263 pkcs7->privateKeySz = keySz;
13264
13265 return 0;
13266}
13267
13268
13269#if 0
13270/* append data to encrypted content cache in PKCS7 structure
13271 * return 0 on success, negative on error */
13272static int PKCS7_CacheEncryptedContent(wc_PKCS7* pkcs7, byte* in, word32 inSz)
13273{
13274 byte* oldCache;
13275 word32 oldCacheSz;
13276
13277 if (pkcs7 == NULL || in == NULL)
13278 return BAD_FUNC_ARG;
13279
13280 /* save pointer to old cache */
13281 oldCache = pkcs7->cachedEncryptedContent;
13282 oldCacheSz = pkcs7->cachedEncryptedContentSz;
13283
13284 /* re-allocate new buffer to fit appended data */
13285 pkcs7->cachedEncryptedContent = (byte*)XMALLOC(oldCacheSz + inSz,
13286 pkcs7->heap, DYNAMIC_TYPE_PKCS7);
13287 if (pkcs7->cachedEncryptedContent == NULL) {
13288 pkcs7->cachedEncryptedContentSz = 0;
13289 XFREE(oldCache, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
13290 return MEMORY_E;
13291 }
13292
13293 if (oldCache != NULL) {
13294 XMEMCPY(pkcs7->cachedEncryptedContent, oldCache, oldCacheSz);
13295 }
13296 XMEMCPY(pkcs7->cachedEncryptedContent + oldCacheSz, in, inSz);
13297 pkcs7->cachedEncryptedContentSz += inSz;
13298
13299 XFREE(oldCache, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
13300
13301 return 0;
13302}
13303#endif
13304
13305
13306/* unwrap and decrypt PKCS#7 envelopedData object, return decoded size */
13307int wc_PKCS7_DecodeEnvelopedData(wc_PKCS7* pkcs7, byte* in,
13308 word32 inSz, byte* output,
13309 word32 outputSz)
13310{
13311 int recipFound = 0;
13312 int ret, length = 0;
13313 word32 idx = 0;
13314 word32 tmpIdx = 0;
13315 word32 recipientSetSz = 0;
13316 word32 contentType = 0, encOID = 0;
13317 word32 decryptedKeySz = MAX_ENCRYPTED_KEY_SZ;
13318
13319 int expBlockSz = 0, blockKeySz = 0;
13320 byte tmpIvBuf[MAX_CONTENT_IV_SIZE];
13321 byte* tmpIv = tmpIvBuf;
13322
13323 byte* pkiMsg = in;
13324 word32 pkiMsgSz = inSz;
13325 byte* decryptedKey = NULL;
13326 int encryptedContentTotalSz = 0;
13327 int encryptedContentSz = 0;
13328 byte padLen;
13329 byte* encryptedContent = NULL;
13330 int explicitOctet = 0;
13331 word32 localIdx = 0;
13332 byte tag = 0;
13333 byte padCheck = 0;
13334 int padIndex;
13335
13336 if (pkcs7 == NULL)
13337 return BAD_FUNC_ARG;
13338
13339 if (pkiMsg == NULL || pkiMsgSz == 0)
13340 return BAD_FUNC_ARG;
13341
13342 if ((output == NULL || outputSz == 0)
13343 #ifdef ASN_BER_TO_DER
13344 && pkcs7->streamOutCb == NULL
13345 #endif
13346 ) {
13347 return BAD_FUNC_ARG;
13348 }
13349
13350#ifndef NO_PKCS7_STREAM
13351 (void)tmpIv; /* help out static analysis */
13352 if (pkcs7->stream == NULL) {
13353 if ((ret = wc_PKCS7_CreateStream(pkcs7)) != 0) {
13354 return ret;
13355 }
13356 }
13357#endif
13358
13359 switch (pkcs7->state) {
13360 case WC_PKCS7_START:
13361 case WC_PKCS7_INFOSET_START:
13362 case WC_PKCS7_INFOSET_STAGE1:
13363 case WC_PKCS7_INFOSET_STAGE2:
13364 case WC_PKCS7_INFOSET_END:
13365 ret = wc_PKCS7_ParseToRecipientInfoSet(pkcs7, pkiMsg, pkiMsgSz,
13366 &idx, ENVELOPED_DATA);
13367 if (ret < 0) {
13368 break;
13369 }
13370
13371 decryptedKey = (byte*)XMALLOC(MAX_ENCRYPTED_KEY_SZ, pkcs7->heap,
13372 DYNAMIC_TYPE_PKCS7);
13373 if (decryptedKey == NULL)
13374 return MEMORY_E;
13375 XMEMSET(decryptedKey, 0, MAX_ENCRYPTED_KEY_SZ);
13376 #ifdef WOLFSSL_CHECK_MEM_ZERO
13377 wc_MemZero_Add("wc_PKCS7 decryptedKey", decryptedKey,
13378 MAX_ENCRYPTED_KEY_SZ);
13379 #endif
13380 wc_PKCS7_ChangeState(pkcs7, WC_PKCS7_ENV_2);
13381 tmpIdx = idx;
13382 recipientSetSz = (word32)ret;
13383 #ifndef NO_PKCS7_STREAM
13384 pkcs7->stream->aad = decryptedKey;
13385 /* get the full recipient set */
13386 pkcs7->stream->expected = recipientSetSz;
13387 pkcs7->stream->recipientSz = ret;
13388 #endif
13389 FALL_THROUGH;
13390
13391 case WC_PKCS7_ENV_2:
13392 #ifndef NO_PKCS7_STREAM
13393 /* store up enough buffer for initial info set decode */
13394 if ((ret = wc_PKCS7_AddDataToStream(pkcs7, in, inSz,
13395 pkcs7->stream->expected, &pkiMsg, &idx)) != 0) {
13396 return ret;
13397 }
13398 #endif
13399 FALL_THROUGH;
13400
13401 case WC_PKCS7_DECRYPT_KTRI:
13402 case WC_PKCS7_DECRYPT_KTRI_2:
13403 case WC_PKCS7_DECRYPT_KTRI_3:
13404 case WC_PKCS7_DECRYPT_KARI:
13405 case WC_PKCS7_DECRYPT_KEKRI:
13406 case WC_PKCS7_DECRYPT_PWRI:
13407 case WC_PKCS7_DECRYPT_ORI:
13408 #ifndef NO_PKCS7_STREAM
13409 decryptedKey = pkcs7->stream->aad;
13410 decryptedKeySz = MAX_ENCRYPTED_KEY_SZ;
13411 tmpIdx = idx;
13412 #endif
13413 ret = wc_PKCS7_DecryptRecipientInfos(pkcs7, in, inSz, &idx,
13414 decryptedKey, &decryptedKeySz,
13415 &recipFound);
13416 if (ret == 0 && recipFound == 0) {
13417 WOLFSSL_MSG(
13418 "No recipient found in envelopedData that matches input");
13419 ret = PKCS7_RECIP_E;
13420 }
13421
13422 if (ret != 0)
13423 break;
13424 #ifndef NO_PKCS7_STREAM
13425 /* advance idx past recipient info set if not all recipients
13426 * parsed */
13427 if (pkcs7->stream->totalRd < ((word32)pkcs7->stream->recipientSz +
13428 tmpIdx)) {
13429 idx = tmpIdx + (word32)pkcs7->stream->recipientSz;
13430
13431 /* process additional recipients as read */
13432 if ((ret = wc_PKCS7_StreamEndCase(pkcs7, &tmpIdx, &idx)) != 0) {
13433 break;
13434 }
13435 }
13436
13437 tmpIdx = idx;
13438 pkcs7->stream->aadSz = decryptedKeySz;
13439 pkcs7->stream->expected = MAX_LENGTH_SZ + MAX_VERSION_SZ +
13440 ASN_TAG_SZ + MAX_LENGTH_SZ;
13441 #else
13442 idx = tmpIdx + recipientSetSz;
13443 #endif
13444 wc_PKCS7_ChangeState(pkcs7, WC_PKCS7_ENV_3);
13445 FALL_THROUGH;
13446
13447 case WC_PKCS7_ENV_3:
13448
13449 #ifndef NO_PKCS7_STREAM
13450 if ((ret = wc_PKCS7_AddDataToStream(pkcs7, in, inSz,
13451 pkcs7->stream->expected, &pkiMsg, &idx)) != 0) {
13452 return ret;
13453 }
13454 pkiMsgSz = (pkcs7->stream->length > 0)? pkcs7->stream->length: inSz;
13455 #else
13456 ret = 0;
13457 #endif
13458
13459 /* remove EncryptedContentInfo */
13460 if (GetSequence_ex(pkiMsg, &idx, &length, pkiMsgSz,
13461 NO_USER_CHECK) < 0) {
13462 ret = ASN_PARSE_E;
13463 }
13464
13465 #ifndef NO_PKCS7_STREAM
13466 if (length == 0) {
13467 /* if indefinite length, assume worst case size
13468 * - Content Type OID + tag/length
13469 * - Algorithm ID structure (OID + parameters)
13470 * - Version
13471 */
13472 pkcs7->stream->expected = MAX_SEQ_SZ + /* outer sequence */
13473 MAX_OID_SZ + /* content type OID */
13474 MAX_ALGO_SZ + /* algo identifier */
13475 MAX_VERSION_SZ +/* version */
13476 ASN_TAG_SZ + /* tag */
13477 MAX_LENGTH_SZ; /* length */
13478 }
13479 else {
13480 /* revize expected size if known */
13481 pkcs7->stream->expected = (word32)length + ASN_TAG_SZ;
13482 }
13483
13484 /* Did we get enough for the expected length? */
13485 if (pkcs7->stream->expected > pkiMsgSz) {
13486 localIdx = idx;
13487 if ((ret = wc_PKCS7_AddDataToStream(pkcs7, in, inSz,
13488 pkcs7->stream->expected, &pkiMsg, &idx)) != 0) {
13489 return ret;
13490 }
13491 pkiMsgSz = (pkcs7->stream->length > 0)? pkcs7->stream->length:
13492 inSz;
13493 if (pkcs7->stream->length > 0) {
13494 idx = localIdx; /* account for byte used with seq read */
13495 }
13496 }
13497 #endif
13498
13499 if (ret == 0 && wc_GetContentType(pkiMsg, &idx, &contentType,
13500 pkiMsgSz) < 0) {
13501 ret = ASN_PARSE_E;
13502 }
13503
13504 if (ret == 0) {
13505 pkcs7->contentOID = (int)contentType;
13506 }
13507
13508 if (ret == 0 && GetAlgoId(pkiMsg, &idx, &encOID, oidBlkType,
13509 pkiMsgSz) < 0) {
13510 ret = ASN_PARSE_E;
13511 }
13512
13513 blockKeySz = wc_PKCS7_GetOIDKeySize((int)encOID);
13514 if (ret == 0 && blockKeySz < 0) {
13515 ret = blockKeySz;
13516 }
13517
13518 expBlockSz = wc_PKCS7_GetOIDBlockSize((int)encOID);
13519 if (ret == 0 && expBlockSz < 0) {
13520 ret = expBlockSz;
13521 }
13522
13523 /* get block cipher IV, stored in OPTIONAL parameter of AlgoID */
13524 if (ret == 0 && GetASNTag(pkiMsg, &idx, &tag, pkiMsgSz) != 0) {
13525 ret = ASN_PARSE_E;
13526 }
13527
13528 if (ret == 0 && tag != ASN_OCTET_STRING) {
13529 ret = ASN_PARSE_E;
13530 }
13531
13532 if (ret == 0 && GetLength_ex(pkiMsg, &idx, &length, pkiMsgSz,
13533 NO_USER_CHECK) < 0) {
13534 ret = ASN_PARSE_E;
13535 }
13536
13537 if (ret == 0 && length != expBlockSz) {
13538 WOLFSSL_MSG(
13539 "Incorrect IV length, must be of content alg block size");
13540 ret = ASN_PARSE_E;
13541 }
13542
13543 if (ret != 0)
13544 break;
13545 #ifndef NO_PKCS7_STREAM
13546 if ((ret = wc_PKCS7_StreamEndCase(pkcs7, &tmpIdx, &idx)) != 0) {
13547 break;
13548 }
13549 wc_PKCS7_StreamStoreVar(pkcs7, encOID, expBlockSz, length);
13550 pkcs7->stream->contentSz = (word32)blockKeySz;
13551 pkcs7->stream->expected = (word32)length + MAX_LENGTH_SZ +
13552 MAX_LENGTH_SZ + ASN_TAG_SZ + ASN_TAG_SZ;
13553 #endif
13554 wc_PKCS7_ChangeState(pkcs7, WC_PKCS7_ENV_4);
13555 FALL_THROUGH;
13556
13557 case WC_PKCS7_ENV_4:
13558
13559 #ifndef NO_PKCS7_STREAM
13560 if ((ret = wc_PKCS7_AddDataToStream(pkcs7, in, inSz,
13561 pkcs7->stream->expected, &pkiMsg, &idx)) != 0) {
13562 return ret;
13563 }
13564 pkiMsgSz = (pkcs7->stream->length > 0)? pkcs7->stream->length: inSz;
13565
13566 wc_PKCS7_StreamGetVar(pkcs7, 0, 0, &length);
13567 tmpIv = pkcs7->stream->tmpIv;
13568 if (tmpIv == NULL) {
13569 /* check added to help out static analysis tool */
13570 ret = MEMORY_E;
13571 break;
13572 }
13573 #else
13574 ret = 0;
13575 #endif
13576
13577 XMEMCPY(tmpIv, &pkiMsg[idx], (word32)length);
13578 idx += (word32)length;
13579
13580 explicitOctet = 0;
13581 localIdx = idx;
13582 if (GetASNTag(pkiMsg, &localIdx, &tag, pkiMsgSz) == 0 &&
13583 tag == (ASN_CONTEXT_SPECIFIC | ASN_CONSTRUCTED | 0)) {
13584 explicitOctet = 1;
13585 }
13586
13587 /* read encryptedContent, cont[0] */
13588 if (tag != (ASN_CONTEXT_SPECIFIC | 0) &&
13589 tag != (ASN_CONTEXT_SPECIFIC | ASN_CONSTRUCTED | 0)) {
13590 ret = ASN_PARSE_E;
13591 }
13592 idx++;
13593
13594 if (ret == 0 && GetLength_ex(pkiMsg, &idx, &encryptedContentTotalSz,
13595 pkiMsgSz, 0) < 0) {
13596 ret = ASN_PARSE_E;
13597 }
13598
13599 #ifdef NO_PKCS7_STREAM
13600 if (ret == 0 && encryptedContentTotalSz > (int)(pkiMsgSz - idx)) {
13601 /* In non-streaming mode, ensure the content fits in the buffer.
13602 * Streaming mode handles this via AddDataToStream. */
13603 ret = BUFFER_E;
13604 }
13605 #endif
13606
13607 if (ret != 0)
13608 break;
13609
13610 #ifndef NO_PKCS7_STREAM
13611 if ((ret = wc_PKCS7_StreamEndCase(pkcs7, &tmpIdx, &idx)) != 0) {
13612 break;
13613 }
13614 pkcs7->stream->expected = (word32)encryptedContentTotalSz;
13615 if (explicitOctet) {
13616 pkcs7->stream->expected = MAX_OCTET_STR_SZ;
13617 }
13618 wc_PKCS7_StreamGetVar(pkcs7, &encOID, &expBlockSz, 0);
13619 wc_PKCS7_StreamStoreVar(pkcs7, encOID, expBlockSz, explicitOctet);
13620
13621 if (explicitOctet) {
13622 /* initialize decryption state in preparation. Use
13623 * contentSz (blockKeySz from the content algorithm) as
13624 * the AES key size rather than aadSz (the unwrapped CEK
13625 * length): the two are equal for well-formed messages,
13626 * but using blockKeySz avoids BAD_FUNC_ARG on crafted
13627 * messages where the CEK length does not match the
13628 * content cipher, which would otherwise be a
13629 * distinguishable error. */
13630 if (pkcs7->decryptionCb == NULL) {
13631 ret = wc_PKCS7_DecryptContentInit(pkcs7, encOID,
13632 pkcs7->stream->aad,
13633 (word32)pkcs7->stream->contentSz,
13634 pkcs7->stream->tmpIv, expBlockSz,
13635 pkcs7->devId, pkcs7->heap);
13636 if (ret != 0)
13637 break;
13638 }
13639 }
13640
13641 #endif
13642 pkcs7->totalEncryptedContentSz = 0;
13643 wc_PKCS7_ChangeState(pkcs7, WC_PKCS7_ENV_5);
13644 FALL_THROUGH;
13645
13646 case WC_PKCS7_ENV_5:
13647
13648 #ifndef NO_PKCS7_STREAM
13649
13650 if ((ret = wc_PKCS7_AddDataToStream(pkcs7, in, inSz,
13651 pkcs7->stream->expected, &pkiMsg, &idx)) != 0) {
13652 if (ret != WC_NO_ERR_TRACE(WC_PKCS7_WANT_READ_E)) {
13653 wc_PKCS7_StreamGetVar(pkcs7, &encOID, NULL, NULL);
13654 wc_PKCS7_DecryptContentFree(pkcs7, encOID, pkcs7->heap);
13655 }
13656 return ret;
13657 }
13658
13659 wc_PKCS7_StreamGetVar(pkcs7, &encOID, &expBlockSz, &explicitOctet);
13660 tmpIv = pkcs7->stream->tmpIv;
13661 encryptedContentTotalSz = (int)pkcs7->stream->expected;
13662
13663 pkiMsgSz = (pkcs7->stream->length > 0)? pkcs7->stream->length: inSz;
13664
13665 /* restore decrypted key */
13666 decryptedKey = pkcs7->stream->aad;
13667 decryptedKeySz = pkcs7->stream->aadSz;
13668 blockKeySz = (int)pkcs7->stream->contentSz;
13669 #else
13670 ret = 0;
13671 #endif
13672
13673 if (explicitOctet) {
13674 /* encrypted content may be fragmented into multiple
13675 * consecutive OCTET STRINGs, if so loop through
13676 * decrypting and outputting or caching contents until the indef
13677 * ending tag is found */
13678
13679 while (1) {
13680 encryptedContentSz = 0;
13681 if (pkiMsgSz <= localIdx + MAX_OCTET_STR_SZ) {
13682 #ifndef NO_PKCS7_STREAM
13683 /* ran out of data to parse */
13684 if ((ret = wc_PKCS7_AddDataToStream(pkcs7, in, inSz,
13685 pkcs7->stream->expected, &pkiMsg, &idx)) != 0) {
13686 break;
13687 }
13688 pkiMsgSz = (pkcs7->stream->length > 0) ?
13689 pkcs7->stream->length : inSz;
13690 #else
13691 ret = BUFFER_E;
13692 #endif
13693 }
13694
13695 localIdx = idx;
13696 if (GetASNTag(pkiMsg, &localIdx, &tag, pkiMsgSz) < 0) {
13697 ret = ASN_PARSE_E;
13698 }
13699
13700 if (ret == 0 && (tag != ASN_OCTET_STRING)) {
13701 ret = ASN_PARSE_E;
13702 }
13703
13704 if (ret == 0 && GetLength_ex(pkiMsg, &localIdx,
13705 &encryptedContentSz, pkiMsgSz, 0) <= 0) {
13706 ret = ASN_PARSE_E;
13707 }
13708 #ifndef NO_PKCS7_STREAM
13709 if (ret == 0) {
13710 /* always try to get 2 extra bytes to catch indef ending */
13711 pkcs7->stream->expected = (word32)encryptedContentSz +
13712 (localIdx - idx) + ASN_INDEF_END_SZ;
13713 }
13714 #endif
13715
13716 if (ret == 0 &&
13717 pkcs7->cachedEncryptedContentSz <
13718 (word32)encryptedContentSz) {
13719 if (pkcs7->cachedEncryptedContent != NULL) {
13720 XFREE(pkcs7->cachedEncryptedContent, pkcs7->heap,
13721 DYNAMIC_TYPE_PKCS7);
13722 }
13723 pkcs7->cachedEncryptedContent = (byte*)XMALLOC(
13724 (word32)encryptedContentSz, pkcs7->heap,
13725 DYNAMIC_TYPE_PKCS7);
13726 if (pkcs7->cachedEncryptedContent == NULL) {
13727 ret = MEMORY_E;
13728 }
13729 }
13730 pkcs7->cachedEncryptedContentSz =
13731 (word32)encryptedContentSz;
13732
13733 /* sanity check that the buffer has all of the data */
13734 if (ret == 0 && (localIdx + (word32)encryptedContentSz) >
13735 pkiMsgSz) {
13736 #ifndef NO_PKCS7_STREAM
13737 word32 ofsetIdx = localIdx - idx;
13738 if ((ret = wc_PKCS7_AddDataToStream(pkcs7, in, inSz,
13739 pkcs7->stream->expected, &pkiMsg, &localIdx))
13740 != 0) {
13741 return ret;
13742 }
13743 localIdx += ofsetIdx;
13744 pkiMsgSz = (pkcs7->stream->length > 0)?
13745 pkcs7->stream->length: inSz;
13746 #else
13747 ret = BUFFER_E;
13748 #endif
13749 }
13750
13751 /* Use callback for decryption still, if set */
13752 if (ret == 0 && pkcs7->decryptionCb != NULL) {
13753 ret = pkcs7->decryptionCb(pkcs7, (int)encOID, tmpIv,
13754 expBlockSz, NULL, 0, NULL, 0, &pkiMsg[localIdx],
13755 encryptedContentSz, pkcs7->cachedEncryptedContent,
13756 pkcs7->decryptionCtx);
13757 }
13758
13759 if (ret == 0) {
13760 ret = wc_PKCS7_DecryptContentEx(pkcs7, encOID,
13761 tmpIv, expBlockSz, NULL, 0, NULL, 0,
13762 &pkiMsg[localIdx], encryptedContentSz,
13763 pkcs7->cachedEncryptedContent);
13764 }
13765
13766 #ifndef NO_PKCS7_STREAM
13767 if (ret != 0) {
13768 if (ret == WC_NO_ERR_TRACE(WC_PKCS7_WANT_READ_E)) {
13769 wc_PKCS7_StreamEndCase(pkcs7, &localIdx, &idx);
13770 }
13771 break;
13772 }
13773 #endif
13774
13775 /* advance idx past encrypted content */
13776 localIdx += (word32)encryptedContentSz;
13777
13778 /* keep track of total encrypted content size */
13779 pkcs7->totalEncryptedContentSz +=
13780 (word32)encryptedContentSz;
13781
13782 if (localIdx + ASN_INDEF_END_SZ <= pkiMsgSz) {
13783 if (pkiMsg[localIdx] == ASN_EOC &&
13784 pkiMsg[localIdx+1] == ASN_EOC) {
13785 /* found the end of encrypted content */
13786 localIdx += ASN_INDEF_END_SZ;
13787 break;
13788 }
13789 }
13790 #ifndef NO_PKCS7_STREAM
13791 pkcs7->stream->expected = MAX_OCTET_STR_SZ;
13792 if ((ret = wc_PKCS7_StreamEndCase(pkcs7, &localIdx,
13793 &localIdx)) != 0) {
13794 break;
13795 }
13796 #endif
13797
13798 /* save last decrypted string to handle padding (this output
13799 * flush happens outside of the while loop in the case that
13800 * the indef end was found) */
13801 if (ret == 0) {
13802 #ifdef ASN_BER_TO_DER
13803 if (pkcs7->streamOutCb) {
13804 ret = pkcs7->streamOutCb(pkcs7,
13805 pkcs7->cachedEncryptedContent,
13806 (word32)encryptedContentSz, pkcs7->streamCtx);
13807 }
13808 #endif /* ASN_BER_TO_DER */
13809 }
13810
13811 idx = localIdx;
13812 }
13813
13814 if (ret != 0) {
13815 if (ret != WC_NO_ERR_TRACE(WC_PKCS7_WANT_READ_E)) {
13816 /* free up in an error case if not looking for more
13817 * data */
13818 wc_PKCS7_DecryptContentFree(pkcs7, encOID,
13819 pkcs7->heap);
13820 }
13821 break;
13822 }
13823 wc_PKCS7_DecryptContentFree(pkcs7, encOID, pkcs7->heap);
13824 } else {
13825 word32 tmpSum;
13826 if (!WC_SAFE_SUM_WORD32(idx, (word32)encryptedContentTotalSz, tmpSum) ||
13827 tmpSum > pkiMsgSz) {
13828 ret = BUFFER_E;
13829 break;
13830 }
13831
13832 pkcs7->cachedEncryptedContentSz =
13833 (word32)encryptedContentTotalSz;
13834 pkcs7->totalEncryptedContentSz =
13835 (word32)encryptedContentTotalSz;
13836 pkcs7->cachedEncryptedContent = (byte*)XMALLOC(
13837 pkcs7->cachedEncryptedContentSz, pkcs7->heap,
13838 DYNAMIC_TYPE_PKCS7);
13839
13840 /* decrypt encryptedContent */
13841 ret = wc_PKCS7_DecryptContent(pkcs7, encOID, decryptedKey,
13842 (word32)blockKeySz, tmpIv, expBlockSz, NULL, 0, NULL, 0,
13843 &pkiMsg[idx], encryptedContentTotalSz,
13844 pkcs7->cachedEncryptedContent,
13845 pkcs7->devId, pkcs7->heap);
13846 if (ret != 0) {
13847 break;
13848 }
13849
13850 idx += (word32)encryptedContentTotalSz;
13851 }
13852
13853 /* use cached content */
13854 encryptedContent = pkcs7->cachedEncryptedContent;
13855 encryptedContentSz = (int)pkcs7->cachedEncryptedContentSz;
13856
13857 if (encryptedContentSz <= 0) {
13858 ret = BUFFER_E;
13859 break;
13860 }
13861
13862 padLen = encryptedContent[encryptedContentSz-1];
13863
13864 /* Constant-time padding check */
13865 padCheck |= ctMaskEq(padLen, 0);
13866 padCheck |= ctMaskGT(padLen, expBlockSz);
13867 padCheck |= ctMaskGT(padLen, encryptedContentSz);
13868 padCheck |= ctMaskGT(expBlockSz, encryptedContentSz);
13869 for (padIndex = encryptedContentSz < expBlockSz ? 0 :
13870 encryptedContentSz - expBlockSz;
13871 padIndex < encryptedContentSz; padIndex++) {
13872 byte inPad = ctMaskGTE(padIndex,
13873 encryptedContentSz - (int)padLen);
13874 padCheck |= inPad & (encryptedContent[padIndex] ^ padLen);
13875 }
13876 if (padCheck != 0) {
13877 ret = BUFFER_E;
13878 break;
13879 }
13880
13881 #ifdef ASN_BER_TO_DER
13882 if (pkcs7->streamOutCb) {
13883 ret = pkcs7->streamOutCb(pkcs7, encryptedContent,
13884 (word32)encryptedContentSz - padLen,
13885 pkcs7->streamCtx);
13886 if (ret != 0) {
13887 WOLFSSL_MSG("Stream out callback returned failure");
13888 ret = BUFFER_E;
13889 break;
13890 }
13891 }
13892 else
13893 #endif /* ASN_BER_TO_DER */
13894 {
13895 if (output == NULL || (word32)(encryptedContentSz - padLen) >
13896 outputSz) {
13897 ret = BUFFER_E;
13898 break;
13899 }
13900 XMEMCPY(output, encryptedContent,
13901 (word32)encryptedContentSz - padLen);
13902 }
13903
13904 /* free memory, zero out keys */
13905 ForceZero(decryptedKey, MAX_ENCRYPTED_KEY_SZ);
13906 XFREE(decryptedKey, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
13907 if (pkcs7->cachedEncryptedContent != NULL) {
13908 XFREE(pkcs7->cachedEncryptedContent, pkcs7->heap,
13909 DYNAMIC_TYPE_PKCS7);
13910 pkcs7->cachedEncryptedContent = NULL;
13911 pkcs7->cachedEncryptedContentSz = 0;
13912 }
13913
13914 ret = (int)pkcs7->totalEncryptedContentSz - padLen;
13915 #ifndef NO_PKCS7_STREAM
13916 /* decryptedKey (just freed) is the same buffer stream->aad
13917 * aliases. Null the stream handle so ResetStream doesn't
13918 * double-free it. */
13919 if (pkcs7->stream != NULL) {
13920 pkcs7->stream->aad = NULL;
13921 pkcs7->stream->aadSz = 0;
13922 }
13923 wc_PKCS7_ResetStream(pkcs7);
13924 #endif
13925 wc_PKCS7_ChangeState(pkcs7, WC_PKCS7_START);
13926 break;
13927
13928 default:
13929 WOLFSSL_MSG("PKCS#7 unknown decode enveloped state");
13930 ret = BAD_FUNC_ARG;
13931 }
13932
13933#ifndef NO_PKCS7_STREAM
13934 if (ret < 0 && ret != WC_NO_ERR_TRACE(WC_PKCS7_WANT_READ_E)) {
13935 /* stream->aad aliases the MAX_ENCRYPTED_KEY_SZ decryptedKey
13936 * buffer in this flow. ResetStream only zeros aadSz bytes, so
13937 * explicitly zero and release the full buffer here to satisfy
13938 * WOLFSSL_CHECK_MEM_ZERO and avoid leaking key material. */
13939 if (pkcs7->stream != NULL && pkcs7->stream->aad != NULL) {
13940 ForceZero(pkcs7->stream->aad, MAX_ENCRYPTED_KEY_SZ);
13941 XFREE(pkcs7->stream->aad, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
13942 pkcs7->stream->aad = NULL;
13943 pkcs7->stream->aadSz = 0;
13944 }
13945 wc_PKCS7_ResetStream(pkcs7);
13946 wc_PKCS7_ChangeState(pkcs7, WC_PKCS7_START);
13947 if (pkcs7->cachedEncryptedContent != NULL) {
13948 XFREE(pkcs7->cachedEncryptedContent, pkcs7->heap,
13949 DYNAMIC_TYPE_PKCS7);
13950 pkcs7->cachedEncryptedContent = NULL;
13951 pkcs7->cachedEncryptedContentSz = 0;
13952 }
13953 }
13954#else
13955 if (ret < 0) {
13956 wc_PKCS7_ChangeState(pkcs7, WC_PKCS7_START);
13957 }
13958 if (decryptedKey != NULL && ret < 0) {
13959 ForceZero(decryptedKey, MAX_ENCRYPTED_KEY_SZ);
13960 XFREE(decryptedKey, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
13961 }
13962 if (pkcs7->cachedEncryptedContent != NULL && ret < 0) {
13963 XFREE(pkcs7->cachedEncryptedContent, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
13964 pkcs7->cachedEncryptedContent = NULL;
13965 pkcs7->cachedEncryptedContentSz = 0;
13966 }
13967#endif
13968 return ret;
13969}
13970
13971
13972int wc_PKCS7_GetEnvelopedDataKariRid(const byte * in, word32 inSz,
13973 byte * out, word32 * outSz)
13974{
13975 int ret = 0;
13976 word32 idx = 0;
13977 int length = 0;
13978 word32 contentType = 0;
13979 word32 ridIdx = 0;
13980 byte ridTag = 0;
13981
13982 if (in == NULL || inSz == 0 || out == NULL || outSz == NULL) {
13983 ret = BAD_FUNC_ARG;
13984 }
13985 /* Consume ContentInfo SEQUENCE header. */
13986 else if (GetSequence(in, &idx, &length, inSz) < 0) {
13987 ret = ASN_PARSE_E;
13988 }
13989 /* Validate the EnvelopedData OBJECT IDENTIFIER. */
13990 else if (wc_GetContentType(in, &idx, &contentType, inSz) < 0) {
13991 ret = ASN_PARSE_E;
13992 }
13993 else if (contentType != ENVELOPED_DATA) {
13994 WOLFSSL_MSG("PKCS#7 input not of type EnvelopedData");
13995 ret = PKCS7_OID_E;
13996 }
13997 /* Consume EXPLICIT content [0] header. */
13998 else if (GetASNHeader(in, ASN_CONTEXT_SPECIFIC | ASN_CONSTRUCTED, &idx,
13999 &length, inSz) < 0) {
14000 ret = ASN_PARSE_E;
14001 }
14002 /* Consume EnvelopedData SEQUENCE header. */
14003 else if (GetSequence(in, &idx, &length, inSz) < 0) {
14004 ret = ASN_PARSE_E;
14005 }
14006 /* Consume version. */
14007 else if (GetMyVersion(in, &idx, &length, inSz) < 0) {
14008 ret = ASN_PARSE_E;
14009 }
14010 /* Consume originatorInfo if present. */
14011 else if (GetASNHeader(in, ASN_CONTEXT_SPECIFIC | ASN_CONSTRUCTED, &idx,
14012 &length, inSz) >= 0) {
14013 idx += (word32)length;
14014 }
14015 /* Consume recipientInfos SET OF header. */
14016 if (ret == 0 && GetSet(in, &idx, &length, inSz) < 0) {
14017 ret = ASN_PARSE_E;
14018 }
14019 /* Consume kari [1] header. */
14020 if (ret == 0 && GetASNHeader(in, ASN_CONTEXT_SPECIFIC | ASN_CONSTRUCTED | 1,
14021 &idx, &length, inSz) < 0) {
14022 ret = ASN_PARSE_E;
14023 }
14024 /* Consume KARI version. */
14025 if (ret == 0 && GetMyVersion(in, &idx, &length, inSz) < 0) {
14026 ret = ASN_PARSE_E;
14027 }
14028 /* Consume KARI originator [0] header. */
14029 if (ret == 0 && GetASNHeader(in, ASN_CONTEXT_SPECIFIC | ASN_CONSTRUCTED,
14030 &idx, &length, inSz) < 0) {
14031 ret = ASN_PARSE_E;
14032 }
14033 /* Skip originator [0] content. */
14034 if (ret == 0)
14035 idx += (word32)length;
14036 /* Consume KARI ukm [1] if present. */
14037 if (ret == 0 && GetASNHeader(in, ASN_CONTEXT_SPECIFIC | ASN_CONSTRUCTED | 1,
14038 &idx, &length, inSz) >= 0) {
14039 idx += (word32) length;
14040 }
14041 /* Consume KARI keyEncryptionAlgorithm. */
14042 if (ret == 0 && GetSequence(in, &idx, &length, inSz) < 0) {
14043 ret = ASN_PARSE_E;
14044 }
14045 /* Skip keyEncryptionAlgorithm content. */
14046 if (ret == 0)
14047 idx += (word32)length;
14048 /* Consume RecipientEncryptedKeys SEQUENCE OF header. */
14049 if (ret == 0 && GetSequence(in, &idx, &length, inSz) < 0) {
14050 ret = ASN_PARSE_E;
14051 }
14052 /* Consume RecipientEncryptedKey SEQUENCE header. */
14053 if (ret == 0 && GetSequence(in, &idx, &length, inSz) < 0) {
14054 ret = ASN_PARSE_E;
14055 }
14056 if (ret == 0)
14057 ridIdx = idx;
14058 /* Consume KeyAgreeRecipientIdentifier tag. */
14059 if (ret == 0 && GetASNTag(in, &idx, &ridTag, inSz) < 0) {
14060 ret = ASN_PARSE_E;
14061 }
14062 /* Consume KeyAgreeRecipientIdentifier length. */
14063 if (ret == 0 && GetLength(in, &idx, &length, inSz) < 0) {
14064 ret = ASN_PARSE_E;
14065 }
14066 if (ret == 0) {
14067 word32 ridSz = (idx + (word32)length) - ridIdx;
14068 if (ridSz > *outSz) {
14069 /* Not enough room in output buffer. */
14070 ret = BUFFER_E;
14071 }
14072 else {
14073 /* Copy KeyAgreeRecipientIdentifier to output buffer. */
14074 XMEMCPY(out, &in[ridIdx], ridSz);
14075 *outSz = ridSz;
14076 }
14077 }
14078 return ret;
14079}
14080
14081
14082/* build PKCS#7 authEnvelopedData content type, return enveloped size */
14083int wc_PKCS7_EncodeAuthEnvelopedData(wc_PKCS7* pkcs7, byte* output,
14084 word32 outputSz)
14085{
14086#if defined(HAVE_AESGCM) || defined(HAVE_AESCCM)
14087 int ret, idx = 0;
14088 int totalSz, encryptedAllocSz, encryptedOutSz;
14089
14090 int contentInfoSeqSz, outerContentTypeSz, outerContentSz;
14091 byte contentInfoSeq[MAX_SEQ_SZ];
14092 byte outerContentType[MAX_ALGO_SZ];
14093 byte outerContent[MAX_SEQ_SZ];
14094
14095 int envDataSeqSz, verSz;
14096 byte envDataSeq[MAX_SEQ_SZ];
14097 byte ver[MAX_VERSION_SZ];
14098
14099 WC_RNG rng;
14100 int blockSz, blockKeySz;
14101 byte* plain;
14102 byte* encryptedContent;
14103
14104 Pkcs7EncodedRecip* tmpRecip = NULL;
14105 int recipSz, recipSetSz;
14106 byte recipSet[MAX_SET_SZ];
14107
14108 int encContentOctetSz, encContentSeqSz, contentTypeSz;
14109 int contentEncAlgoSz, nonceOctetStringSz, macOctetStringSz;
14110 byte encContentSeq[MAX_SEQ_SZ];
14111 byte contentType[MAX_ALGO_SZ];
14112 byte contentEncAlgo[MAX_ALGO_SZ];
14113 byte nonceOctetString[MAX_OCTET_STR_SZ];
14114 byte encContentOctet[MAX_OCTET_STR_SZ];
14115 byte macOctetString[MAX_OCTET_STR_SZ];
14116
14117 byte authTag[WC_AES_BLOCK_SIZE];
14118 byte nonce[GCM_NONCE_MID_SZ]; /* GCM nonce is larger than CCM */
14119 byte macInt[MAX_VERSION_SZ];
14120 byte algoParamSeq[MAX_SEQ_SZ];
14121 word32 nonceSz = 0, macIntSz = 0, algoParamSeqSz = 0;
14122
14123 /* authAttribs */
14124 byte* flatAuthAttribs = NULL;
14125 byte authAttribSet[MAX_SET_SZ];
14126 EncodedAttrib authAttribs[MAX_AUTH_ATTRIBS_SZ];
14127 word32 authAttribsSz = 0, authAttribsCount = 0;
14128 word32 authAttribsSetSz = 0;
14129
14130 byte* aadBuffer = NULL;
14131 word32 aadBufferSz = 0;
14132 byte authAttribAadSet[MAX_SET_SZ];
14133 word32 authAttribsAadSetSz = 0;
14134
14135 /* unauthAttribs */
14136 byte* flatUnauthAttribs = NULL;
14137 byte unauthAttribSet[MAX_SET_SZ];
14138 EncodedAttrib unauthAttribs[MAX_UNAUTH_ATTRIBS_SZ];
14139 word32 unauthAttribsSz = 0, unauthAttribsCount = 0;
14140 word32 unauthAttribsSetSz = 0;
14141
14142
14143 PKCS7Attrib contentTypeAttrib;
14144 byte contentTypeValue[MAX_OID_SZ];
14145 /* contentType OID (1.2.840.113549.1.9.3) */
14146 const byte contentTypeOid[] =
14147 { ASN_OBJECT_ID, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xF7, 0x0d, 0x01,
14148 0x09, 0x03 };
14149 if (pkcs7 == NULL || pkcs7->content == NULL || pkcs7->contentSz == 0)
14150 return BAD_FUNC_ARG;
14151
14152 if (output == NULL || outputSz == 0)
14153 return BAD_FUNC_ARG;
14154
14155 switch (pkcs7->encryptOID) {
14156#ifdef HAVE_AESGCM
14157 #ifdef WOLFSSL_AES_128
14158 case AES128GCMb:
14159 break;
14160 #endif
14161 #ifdef WOLFSSL_AES_192
14162 case AES192GCMb:
14163 break;
14164 #endif
14165 #ifdef WOLFSSL_AES_256
14166 case AES256GCMb:
14167 break;
14168 #endif
14169#endif
14170#ifdef HAVE_AESCCM
14171 #ifdef WOLFSSL_AES_128
14172 case AES128CCMb:
14173 break;
14174 #endif
14175 #ifdef WOLFSSL_AES_192
14176 case AES192CCMb:
14177 break;
14178 #endif
14179 #ifdef WOLFSSL_AES_256
14180 case AES256CCMb:
14181 break;
14182 #endif
14183#endif
14184 default:
14185 WOLFSSL_MSG("CMS AuthEnvelopedData must use AES-GCM or AES-CCM");
14186 return BAD_FUNC_ARG;
14187 }
14188
14189 blockKeySz = wc_PKCS7_GetOIDKeySize(pkcs7->encryptOID);
14190 if (blockKeySz < 0)
14191 return blockKeySz;
14192
14193 blockSz = wc_PKCS7_GetOIDBlockSize(pkcs7->encryptOID);
14194 if (blockSz < 0)
14195 return blockSz;
14196
14197 /* outer content type */
14198 ret = wc_SetContentType(AUTH_ENVELOPED_DATA, outerContentType,
14199 sizeof(outerContentType));
14200 if (ret < 0)
14201 return ret;
14202
14203 outerContentTypeSz = ret;
14204
14205 /* version, defined as 0 in RFC 5083 */
14206 verSz = SetMyVersion(0, ver, 0);
14207
14208 /* generate random content encryption key */
14209 ret = PKCS7_GenerateContentEncryptionKey(pkcs7, (word32)blockKeySz);
14210 if (ret != 0) {
14211 return ret;
14212 }
14213
14214 /* build RecipientInfo, only if user manually set singleCert and size */
14215 if (pkcs7->singleCert != NULL && pkcs7->singleCertSz > 0) {
14216 switch (pkcs7->publicKeyOID) {
14217 #ifndef NO_RSA
14218 #ifdef WC_RSA_PSS
14219 case RSAPSSk:
14220 FALL_THROUGH;
14221 #endif
14222 case RSAk:
14223 ret = wc_PKCS7_AddRecipient_KTRI(pkcs7, pkcs7->singleCert,
14224 pkcs7->singleCertSz, 0);
14225 break;
14226 #endif
14227 #ifdef HAVE_ECC
14228 case ECDSAk:
14229 ret = wc_PKCS7_AddRecipient_KARI(pkcs7, pkcs7->singleCert,
14230 pkcs7->singleCertSz,
14231 pkcs7->keyWrapOID,
14232 pkcs7->keyAgreeOID, pkcs7->ukm,
14233 pkcs7->ukmSz, 0);
14234 break;
14235 #endif
14236
14237 default:
14238 WOLFSSL_MSG("Unsupported RecipientInfo public key type");
14239 return BAD_FUNC_ARG;
14240 };
14241
14242 if (ret < 0) {
14243 WOLFSSL_MSG("Failed to create RecipientInfo");
14244 return ret;
14245 }
14246 }
14247
14248 recipSz = wc_PKCS7_GetRecipientListSize(pkcs7);
14249 if (recipSz < 0) {
14250 return ret;
14251
14252 } else if (recipSz == 0) {
14253 WOLFSSL_MSG("You must add at least one CMS recipient");
14254 return PKCS7_RECIP_E;
14255 }
14256 recipSetSz = (int)SetSet((word32)recipSz, recipSet);
14257
14258 /* generate random nonce and IV for encryption */
14259 switch (pkcs7->encryptOID) {
14260#ifdef HAVE_AESGCM
14261 #ifdef WOLFSSL_AES_128
14262 case AES128GCMb:
14263 #endif
14264 #ifdef WOLFSSL_AES_192
14265 case AES192GCMb:
14266 #endif
14267 #ifdef WOLFSSL_AES_256
14268 case AES256GCMb:
14269 #endif
14270 #if defined(WOLFSSL_AES_128) || defined(WOLFSSL_AES_192) || \
14271 defined(WOLFSSL_AES_256)
14272 /* GCM nonce is GCM_NONCE_MID_SZ (12) */
14273 nonceSz = GCM_NONCE_MID_SZ;
14274 break;
14275 #endif
14276#endif /* HAVE_AESGCM */
14277#ifdef HAVE_AESCCM
14278 #ifdef WOLFSSL_AES_128
14279 case AES128CCMb:
14280 #endif
14281 #ifdef WOLFSSL_AES_192
14282 case AES192CCMb:
14283 #endif
14284 #ifdef WOLFSSL_AES_256
14285 case AES256CCMb:
14286 #endif
14287 #if defined(WOLFSSL_AES_128) || defined(WOLFSSL_AES_192) || \
14288 defined(WOLFSSL_AES_256)
14289 /* CCM nonce is CCM_NONCE_MIN_SZ (7) */
14290 nonceSz = CCM_NONCE_MIN_SZ;
14291 break;
14292 #endif
14293#endif /* HAVE_AESCCM */
14294 }
14295
14296 ret = wc_InitRng_ex(&rng, pkcs7->heap, pkcs7->devId);
14297 if (ret != 0) {
14298 wc_PKCS7_FreeEncodedRecipientSet(pkcs7);
14299 return ret;
14300 }
14301
14302 ret = wc_PKCS7_GenerateBlock(pkcs7, &rng, nonce, nonceSz);
14303 wc_FreeRng(&rng);
14304 if (ret != 0) {
14305 wc_PKCS7_FreeEncodedRecipientSet(pkcs7);
14306 return ret;
14307 }
14308
14309
14310 /* authAttribs: add contentType attrib if needed */
14311 if (pkcs7->contentOID != DATA) {
14312
14313 XMEMSET(&contentTypeAttrib, 0, sizeof contentTypeAttrib);
14314
14315 /* if type is not id-data, contentType attribute MUST be added */
14316 contentTypeAttrib.oid = contentTypeOid;
14317 contentTypeAttrib.oidSz = sizeof(contentTypeOid);
14318
14319 /* try to set from contentOID first, known types */
14320 ret = wc_SetContentType(pkcs7->contentOID, contentTypeValue,
14321 sizeof(contentTypeValue));
14322 if (ret > 0) {
14323 contentTypeAttrib.value = contentTypeValue;
14324 contentTypeAttrib.valueSz = (word32)ret;
14325
14326 /* otherwise, try to set from custom content type */
14327 } else {
14328 if (pkcs7->contentTypeSz == 0) {
14329 WOLFSSL_MSG("CMS pkcs7->contentType must be set if "
14330 "contentOID is not");
14331 wc_PKCS7_FreeEncodedRecipientSet(pkcs7);
14332 return BAD_FUNC_ARG;
14333 }
14334 contentTypeAttrib.value = pkcs7->contentType;
14335 contentTypeAttrib.valueSz = pkcs7->contentTypeSz;
14336 }
14337
14338 authAttribsSz += (word32)EncodeAttributes(authAttribs, 1,
14339 &contentTypeAttrib, 1);
14340 authAttribsCount += 1;
14341 }
14342
14343 /* authAttribs: add in user authenticated attributes */
14344 if (pkcs7->authAttribs != NULL && pkcs7->authAttribsSz > 0) {
14345 authAttribsSz += (word32)EncodeAttributes(
14346 authAttribs + authAttribsCount,
14347 (int)(MAX_AUTH_ATTRIBS_SZ - authAttribsCount),
14348 pkcs7->authAttribs,
14349 (int)pkcs7->authAttribsSz);
14350 authAttribsCount += pkcs7->authAttribsSz;
14351 }
14352
14353 /* authAttribs: flatten authAttribs */
14354 if (authAttribsSz > 0 && authAttribsCount > 0) {
14355 flatAuthAttribs = (byte*)XMALLOC(authAttribsSz, pkcs7->heap,
14356 DYNAMIC_TYPE_PKCS7);
14357 if (flatAuthAttribs == NULL) {
14358 wc_PKCS7_FreeEncodedRecipientSet(pkcs7);
14359 return MEMORY_E;
14360 }
14361
14362 ret = FlattenAttributes(pkcs7, flatAuthAttribs, authAttribs,
14363 (int)authAttribsCount);
14364 if (ret != 0) {
14365 wc_PKCS7_FreeEncodedRecipientSet(pkcs7);
14366 XFREE(flatAuthAttribs, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
14367 return ret;
14368 }
14369
14370 authAttribsSetSz = SetImplicit(ASN_SET, 1, authAttribsSz,
14371 authAttribSet, 0);
14372
14373 /* From RFC5083, "For the purpose of constructing the AAD, the
14374 * IMPLICIT [1] tag in the authAttrs field is not used for the
14375 * DER encoding: rather a universal SET OF tag is used. */
14376 authAttribsAadSetSz = SetSet(authAttribsSz, authAttribAadSet);
14377
14378 /* allocate temp buffer to hold alternate attrib encoding for aad */
14379 aadBuffer = (byte*)XMALLOC(authAttribsSz + authAttribsAadSetSz,
14380 pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
14381 if (aadBuffer == NULL) {
14382 wc_PKCS7_FreeEncodedRecipientSet(pkcs7);
14383 XFREE(flatAuthAttribs, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
14384 return MEMORY_E;
14385 }
14386
14387 /* build up alternate attrib encoding for aad */
14388 aadBufferSz = 0;
14389 XMEMCPY(aadBuffer + aadBufferSz, authAttribAadSet, authAttribsAadSetSz);
14390 aadBufferSz += authAttribsAadSetSz;
14391 XMEMCPY(aadBuffer + aadBufferSz, flatAuthAttribs, authAttribsSz);
14392 aadBufferSz += authAttribsSz;
14393 }
14394
14395 /* build up unauthenticated attributes (unauthAttrs) */
14396 if (pkcs7->unauthAttribsSz > 0) {
14397 unauthAttribsSz = (word32)EncodeAttributes(
14398 unauthAttribs + unauthAttribsCount,
14399 (int)(MAX_UNAUTH_ATTRIBS_SZ - unauthAttribsCount),
14400 pkcs7->unauthAttribs,
14401 (int)pkcs7->unauthAttribsSz);
14402 unauthAttribsCount = pkcs7->unauthAttribsSz;
14403
14404 if (unauthAttribsSz > 0) {
14405 flatUnauthAttribs = (byte*)XMALLOC(unauthAttribsSz, pkcs7->heap,
14406 DYNAMIC_TYPE_PKCS7);
14407 if (flatUnauthAttribs == NULL) {
14408 wc_PKCS7_FreeEncodedRecipientSet(pkcs7);
14409 XFREE(aadBuffer, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
14410 XFREE(flatAuthAttribs, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
14411 return MEMORY_E;
14412 }
14413
14414 FlattenAttributes(pkcs7, flatUnauthAttribs, unauthAttribs,
14415 (int)unauthAttribsCount);
14416 }
14417
14418 unauthAttribsSetSz = SetImplicit(ASN_SET, 2, unauthAttribsSz,
14419 unauthAttribSet, 0);
14420 }
14421
14422 /* AES-GCM/CCM does NOT require padding for plaintext content or
14423 * AAD inputs RFC 5084 section 3.1 and 3.2, but we must alloc
14424 * full blocks to ensure crypto only gets full blocks */
14425 encryptedOutSz = (int)pkcs7->contentSz;
14426 encryptedAllocSz = (encryptedOutSz % blockSz) ?
14427 encryptedOutSz + blockSz -
14428 (encryptedOutSz % blockSz) :
14429 encryptedOutSz;
14430
14431 /* Copy content to plain buffer (zero-padded) to encrypt in full,
14432 * contiguous blocks */
14433 plain = (byte*)XMALLOC((word32)encryptedAllocSz, pkcs7->heap,
14434 DYNAMIC_TYPE_PKCS7);
14435 if (plain == NULL) {
14436 wc_PKCS7_FreeEncodedRecipientSet(pkcs7);
14437 XFREE(aadBuffer, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
14438 XFREE(flatUnauthAttribs, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
14439 XFREE(flatAuthAttribs, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
14440 return MEMORY_E;
14441 }
14442
14443 XMEMCPY(plain, pkcs7->content, pkcs7->contentSz);
14444 if ((encryptedAllocSz - encryptedOutSz) > 0) {
14445 XMEMSET(plain + encryptedOutSz, 0,
14446 (word32)(encryptedAllocSz - encryptedOutSz));
14447 }
14448
14449 encryptedContent = (byte*)XMALLOC((word32)encryptedAllocSz, pkcs7->heap,
14450 DYNAMIC_TYPE_PKCS7);
14451 if (encryptedContent == NULL) {
14452 ForceZero(plain, (word32)encryptedAllocSz);
14453 XFREE(plain, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
14454 wc_PKCS7_FreeEncodedRecipientSet(pkcs7);
14455 XFREE(aadBuffer, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
14456 XFREE(flatUnauthAttribs, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
14457 XFREE(flatAuthAttribs, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
14458 return MEMORY_E;
14459 }
14460
14461 /* encrypt content */
14462 ret = wc_PKCS7_EncryptContent(pkcs7, pkcs7->encryptOID, pkcs7->cek,
14463 (int)pkcs7->cekSz, nonce, (int)nonceSz, aadBuffer, aadBufferSz,
14464 authTag, sizeof(authTag), plain, encryptedOutSz, encryptedContent);
14465
14466 ForceZero(plain, (word32)encryptedAllocSz);
14467 XFREE(plain, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
14468 plain = NULL;
14469
14470 XFREE(aadBuffer, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
14471 aadBuffer = NULL;
14472
14473 if (ret != 0) {
14474 wc_PKCS7_FreeEncodedRecipientSet(pkcs7);
14475 XFREE(flatUnauthAttribs, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
14476 XFREE(flatAuthAttribs, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
14477 XFREE(encryptedContent, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
14478 return ret;
14479 }
14480
14481 /* EncryptedContentInfo */
14482 ret = wc_SetContentType(pkcs7->contentOID, contentType,
14483 sizeof(contentType));
14484 if (ret < 0) {
14485 wc_PKCS7_FreeEncodedRecipientSet(pkcs7);
14486 XFREE(flatUnauthAttribs, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
14487 XFREE(flatAuthAttribs, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
14488 XFREE(encryptedContent, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
14489 return ret;
14490 }
14491
14492 contentTypeSz = ret;
14493
14494 /* put together nonce OCTET STRING */
14495 nonceOctetStringSz = (int)SetOctetString(nonceSz, nonceOctetString);
14496
14497 /* put together aes-ICVlen INTEGER */
14498 macIntSz = (word32)SetMyVersion(sizeof(authTag), macInt, 0);
14499
14500 /* add nonce and icv len into parameters string RFC5084 */
14501 algoParamSeqSz = SetSequence((word32)nonceOctetStringSz + nonceSz +
14502 macIntSz, algoParamSeq);
14503
14504 /* build up our ContentEncryptionAlgorithmIdentifier sequence,
14505 * adding (nonceOctetStringSz + blockSz + macIntSz) for nonce OCTET STRING
14506 * and tag size */
14507 contentEncAlgoSz = (int)SetAlgoID(pkcs7->encryptOID, contentEncAlgo,
14508 oidBlkType, nonceOctetStringSz + (int)nonceSz +
14509 (int)macIntSz + (int)algoParamSeqSz);
14510
14511 if (contentEncAlgoSz == 0) {
14512 wc_PKCS7_FreeEncodedRecipientSet(pkcs7);
14513 XFREE(flatUnauthAttribs, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
14514 XFREE(flatAuthAttribs, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
14515 XFREE(encryptedContent, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
14516 return BAD_FUNC_ARG;
14517 }
14518
14519 encContentOctetSz = (int)SetImplicit(ASN_OCTET_STRING, 0,
14520 (word32)encryptedOutSz, encContentOctet, 0);
14521 encContentSeqSz = (int)SetSequence((word32)contentTypeSz +
14522 (word32)contentEncAlgoSz +
14523 (word32)nonceOctetStringSz + nonceSz + macIntSz +
14524 algoParamSeqSz + (word32)encContentOctetSz +
14525 (word32)encryptedOutSz, encContentSeq);
14526
14527 macOctetStringSz = (int)SetOctetString(sizeof(authTag), macOctetString);
14528
14529 /* keep track of sizes for outer wrapper layering */
14530 totalSz = verSz + recipSetSz + recipSz + encContentSeqSz +
14531 contentTypeSz + contentEncAlgoSz + nonceOctetStringSz +
14532 (int)nonceSz + (int)macIntSz + (int)algoParamSeqSz +
14533 encContentOctetSz + encryptedOutSz + (int)authAttribsSz +
14534 (int)authAttribsSetSz + macOctetStringSz + (int)sizeof(authTag) +
14535 (int)unauthAttribsSz + (int)unauthAttribsSetSz;
14536
14537 /* EnvelopedData */
14538 envDataSeqSz = (int)SetSequence((word32)totalSz, envDataSeq);
14539 totalSz += envDataSeqSz;
14540
14541 /* outer content */
14542 outerContentSz = (int)SetExplicit(0, (word32)totalSz, outerContent, 0);
14543 totalSz += outerContentTypeSz;
14544 totalSz += outerContentSz;
14545
14546 /* ContentInfo */
14547 contentInfoSeqSz = (int)SetSequence((word32)totalSz, contentInfoSeq);
14548 totalSz += contentInfoSeqSz;
14549
14550 if (totalSz > (int)outputSz) {
14551 WOLFSSL_MSG("Pkcs7_encrypt output buffer too small");
14552 wc_PKCS7_FreeEncodedRecipientSet(pkcs7);
14553 XFREE(flatUnauthAttribs, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
14554 XFREE(flatAuthAttribs, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
14555 XFREE(encryptedContent, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
14556 return BUFFER_E;
14557 }
14558
14559 XMEMCPY(output + idx, contentInfoSeq, (word32)contentInfoSeqSz);
14560 idx += contentInfoSeqSz;
14561 XMEMCPY(output + idx, outerContentType, (word32)outerContentTypeSz);
14562 idx += outerContentTypeSz;
14563 XMEMCPY(output + idx, outerContent, (word32)outerContentSz);
14564 idx += outerContentSz;
14565 XMEMCPY(output + idx, envDataSeq, (word32)envDataSeqSz);
14566 idx += envDataSeqSz;
14567 XMEMCPY(output + idx, ver, (word32)verSz);
14568 idx += verSz;
14569 XMEMCPY(output + idx, recipSet, (word32)recipSetSz);
14570 idx += recipSetSz;
14571 /* copy in recipients from list */
14572 tmpRecip = pkcs7->recipList;
14573 while (tmpRecip != NULL) {
14574 XMEMCPY(output + idx, tmpRecip->recip, tmpRecip->recipSz);
14575 idx += (int)tmpRecip->recipSz;
14576 tmpRecip = tmpRecip->next;
14577 }
14578 wc_PKCS7_FreeEncodedRecipientSet(pkcs7);
14579 XMEMCPY(output + idx, encContentSeq, (word32)encContentSeqSz);
14580 idx += encContentSeqSz;
14581 XMEMCPY(output + idx, contentType, (word32)contentTypeSz);
14582 idx += contentTypeSz;
14583 XMEMCPY(output + idx, contentEncAlgo, (word32)contentEncAlgoSz);
14584 idx += contentEncAlgoSz;
14585 XMEMCPY(output + idx, algoParamSeq, algoParamSeqSz);
14586 idx += (int)algoParamSeqSz;
14587 XMEMCPY(output + idx, nonceOctetString, (word32)nonceOctetStringSz);
14588 idx += nonceOctetStringSz;
14589 XMEMCPY(output + idx, nonce, nonceSz);
14590 idx += (int)nonceSz;
14591 XMEMCPY(output + idx, macInt, macIntSz);
14592 idx += (int)macIntSz;
14593
14594
14595 XMEMCPY(output + idx, encContentOctet, (word32)encContentOctetSz);
14596 idx += encContentOctetSz;
14597 XMEMCPY(output + idx, encryptedContent, (word32)encryptedOutSz);
14598 idx += encryptedOutSz;
14599
14600 /* authenticated attributes */
14601 if (flatAuthAttribs && authAttribsSz > 0) {
14602 XMEMCPY(output + idx, authAttribSet, authAttribsSetSz);
14603 idx += (int)authAttribsSetSz;
14604 XMEMCPY(output + idx, flatAuthAttribs, authAttribsSz);
14605 idx += (int)authAttribsSz;
14606 XFREE(flatAuthAttribs, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
14607 }
14608
14609 XMEMCPY(output + idx, macOctetString, (word32)macOctetStringSz);
14610 idx += macOctetStringSz;
14611 XMEMCPY(output + idx, authTag, sizeof(authTag));
14612 idx += (int)sizeof(authTag);
14613
14614 /* unauthenticated attributes */
14615 if (unauthAttribsSz > 0) {
14616 XMEMCPY(output + idx, unauthAttribSet, unauthAttribsSetSz);
14617 idx += (int)unauthAttribsSetSz;
14618 XMEMCPY(output + idx, flatUnauthAttribs, unauthAttribsSz);
14619 idx += (int)unauthAttribsSz;
14620 }
14621
14622 XFREE(flatUnauthAttribs, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
14623
14624 XFREE(encryptedContent, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
14625
14626 return idx;
14627
14628#else
14629 WOLFSSL_MSG("AuthEnvelopedData requires AES-GCM or AES-CCM to be enabled");
14630 (void)pkcs7;
14631 (void)output;
14632 (void)outputSz;
14633
14634 return NOT_COMPILED_IN;
14635#endif /* HAVE_AESGCM | HAVE_AESCCM */
14636}
14637
14638
14639/* unwrap and decrypt PKCS#7 AuthEnvelopedData object, return decoded size */
14640int wc_PKCS7_DecodeAuthEnvelopedData(wc_PKCS7* pkcs7, byte* in,
14641 word32 inSz, byte* output,
14642 word32 outputSz)
14643{
14644#if defined(HAVE_AESGCM) || defined(HAVE_AESCCM)
14645 int recipFound = 0;
14646 int ret = 0, length = 0;
14647 word32 idx = 0;
14648#ifndef NO_PKCS7_STREAM
14649 word32 tmpIdx = 0;
14650#endif
14651 word32 contentType = 0, encOID = 0;
14652 word32 decryptedKeySz = 0;
14653 byte* pkiMsg = in;
14654 word32 pkiMsgSz = inSz;
14655
14656 int expBlockSz = 0, blockKeySz = 0;
14657 byte authTag[WC_AES_BLOCK_SIZE];
14658 byte nonce[GCM_NONCE_MID_SZ]; /* GCM nonce is larger than CCM */
14659 int nonceSz = 0, macSz = 0;
14660 word32 authTagSz = 0;
14661 byte* decryptedKey = NULL;
14662 int encryptedContentSz = 0;
14663 int encryptedAllocSz = 0;
14664 byte* encryptedContent = NULL;
14665 int explicitOctet = 0;
14666
14667 byte* encodedAttribs = NULL;
14668 word32 encodedAttribIdx = 0, encodedAttribSz = 0;
14669 byte* authAttrib = NULL;
14670 int authAttribSz = 0;
14671 word32 localIdx;
14672 byte tag = 0;
14673
14674 if (pkcs7 == NULL)
14675 return BAD_FUNC_ARG;
14676
14677 if (pkiMsg == NULL || pkiMsgSz == 0 ||
14678 output == NULL || outputSz == 0)
14679 return BAD_FUNC_ARG;
14680#ifndef NO_PKCS7_STREAM
14681 if (pkcs7->stream == NULL) {
14682 if ((ret = wc_PKCS7_CreateStream(pkcs7)) != 0) {
14683 return ret;
14684 }
14685 }
14686#endif
14687
14688 switch (pkcs7->state) {
14689 case WC_PKCS7_START:
14690 case WC_PKCS7_INFOSET_START:
14691 case WC_PKCS7_INFOSET_STAGE1:
14692 case WC_PKCS7_INFOSET_STAGE2:
14693 case WC_PKCS7_INFOSET_END:
14694 ret = wc_PKCS7_ParseToRecipientInfoSet(pkcs7, pkiMsg, pkiMsgSz,
14695 &idx, AUTH_ENVELOPED_DATA);
14696 if (ret < 0)
14697 break;
14698
14699 #ifndef NO_PKCS7_STREAM
14700 tmpIdx = idx;
14701 #endif
14702 wc_PKCS7_ChangeState(pkcs7, WC_PKCS7_AUTHENV_2);
14703 FALL_THROUGH;
14704
14705 case WC_PKCS7_AUTHENV_2:
14706 #ifndef NO_PKCS7_STREAM
14707 if ((ret = wc_PKCS7_AddDataToStream(pkcs7, in, inSz, MAX_LENGTH_SZ +
14708 MAX_VERSION_SZ + ASN_TAG_SZ, &pkiMsg, &idx)) != 0) {
14709 break;
14710 }
14711 #endif
14712 decryptedKey = (byte*)XMALLOC(MAX_ENCRYPTED_KEY_SZ, pkcs7->heap,
14713 DYNAMIC_TYPE_PKCS7);
14714 if (decryptedKey == NULL) {
14715 ret = MEMORY_E;
14716 break;
14717 }
14718 else {
14719 XMEMSET(decryptedKey, 0, MAX_ENCRYPTED_KEY_SZ);
14720 #ifdef WOLFSSL_CHECK_MEM_ZERO
14721 wc_MemZero_Add("wc_PKCS7 decryptedKey", decryptedKey,
14722 MAX_ENCRYPTED_KEY_SZ);
14723 #endif
14724 }
14725 #ifndef NO_PKCS7_STREAM
14726 pkcs7->stream->key = decryptedKey;
14727 #endif
14728 XMEMSET(decryptedKey, 0, MAX_ENCRYPTED_KEY_SZ);
14729 FALL_THROUGH;
14730
14731 case WC_PKCS7_DECRYPT_KTRI:
14732 case WC_PKCS7_DECRYPT_KTRI_2:
14733 case WC_PKCS7_DECRYPT_KTRI_3:
14734 case WC_PKCS7_DECRYPT_KARI:
14735 case WC_PKCS7_DECRYPT_KEKRI:
14736 case WC_PKCS7_DECRYPT_PWRI:
14737 case WC_PKCS7_DECRYPT_ORI:
14738
14739 decryptedKeySz = MAX_ENCRYPTED_KEY_SZ;
14740 #ifndef NO_PKCS7_STREAM
14741 decryptedKey = pkcs7->stream->key;
14742 #endif
14743
14744 ret = wc_PKCS7_DecryptRecipientInfos(pkcs7, in, inSz, &idx,
14745 decryptedKey, &decryptedKeySz,
14746 &recipFound);
14747 if (ret != 0) {
14748 break;
14749 }
14750
14751 if (recipFound == 0) {
14752 WOLFSSL_MSG(
14753 "No recipient found in envelopedData that matches input");
14754 ret = PKCS7_RECIP_E;
14755 break;
14756 }
14757
14758 #ifndef NO_PKCS7_STREAM
14759 tmpIdx = idx;
14760 pkcs7->stream->expected = MAX_SEQ_SZ;
14761 #endif
14762 wc_PKCS7_ChangeState(pkcs7, WC_PKCS7_AUTHENV_3);
14763 FALL_THROUGH;
14764
14765 case WC_PKCS7_AUTHENV_3:
14766 #ifndef NO_PKCS7_STREAM
14767 if ((ret = wc_PKCS7_AddDataToStream(pkcs7, in, inSz,
14768 pkcs7->stream->expected, &pkiMsg, &idx)) != 0) {
14769 break;
14770 }
14771 pkiMsgSz = (pkcs7->stream->length > 0)? pkcs7->stream->length: inSz;
14772 #endif
14773
14774 /* remove EncryptedContentInfo */
14775 if (ret == 0 && GetSequence_ex(pkiMsg, &idx, &length, pkiMsgSz, 0)
14776 < 0) {
14777 ret = ASN_PARSE_E;
14778 }
14779
14780 #ifndef NO_PKCS7_STREAM
14781 /* check that the expected size was accurate */
14782 if (ret == 0) {
14783 if (length > (int)pkcs7->stream->expected && length >
14784 (int)pkiMsgSz) {
14785 pkcs7->stream->expected = (word32)length + 1;
14786 if ((ret = wc_PKCS7_AddDataToStream(pkcs7, in, inSz,
14787 pkcs7->stream->expected, &pkiMsg, &idx)) != 0) {
14788 break;
14789 }
14790 }
14791 }
14792 #endif
14793
14794 if (ret == 0 && wc_GetContentType(pkiMsg, &idx, &contentType,
14795 pkiMsgSz) < 0) {
14796 ret = ASN_PARSE_E;
14797 }
14798
14799 if (ret == 0) {
14800 pkcs7->contentOID = (int)contentType;
14801 }
14802
14803 if (ret == 0 && GetAlgoId(pkiMsg, &idx, &encOID, oidBlkType,
14804 pkiMsgSz) < 0) {
14805 ret = ASN_PARSE_E;
14806 }
14807
14808 if (ret == 0) {
14809 blockKeySz = wc_PKCS7_GetOIDKeySize((int)encOID);
14810 if (blockKeySz < 0) {
14811 ret = blockKeySz;
14812 }
14813 }
14814
14815 if (ret == 0) {
14816 expBlockSz = wc_PKCS7_GetOIDBlockSize((int)encOID);
14817 if (expBlockSz < 0) {
14818 ret = expBlockSz;
14819 }
14820 }
14821
14822 /* get nonce, stored in OPTIONAL parameter of AlgoID
14823 * RFC 5084 Appendix lists GCM parameters as
14824 * seq
14825 * ---->octet string with nonce
14826 * ---->aes gcm icvlen
14827 */
14828 if (ret == 0 && GetASNTag(pkiMsg, &idx, &tag, pkiMsgSz) < 0) {
14829 ret = ASN_PARSE_E;
14830 }
14831
14832
14833 if (ret == 0 && tag != (ASN_CONSTRUCTED | ASN_SEQUENCE)) {
14834 WOLFSSL_MSG("Optional parameters is not wrapped in a sequence");
14835 ret = ASN_PARSE_E;
14836 }
14837
14838 if (ret < 0)
14839 break;
14840
14841 #ifndef NO_PKCS7_STREAM
14842 if ((ret = wc_PKCS7_StreamEndCase(pkcs7, &tmpIdx, &idx)) != 0) {
14843 break;
14844 }
14845 wc_PKCS7_StreamStoreVar(pkcs7, encOID, blockKeySz, 0);
14846 #endif
14847 wc_PKCS7_ChangeState(pkcs7, WC_PKCS7_AUTHENV_4);
14848 FALL_THROUGH;
14849
14850 case WC_PKCS7_AUTHENV_4:
14851
14852 #ifndef NO_PKCS7_STREAM
14853 if ((ret = wc_PKCS7_AddDataToStream(pkcs7, in, inSz, MAX_LENGTH_SZ +
14854 MAX_VERSION_SZ + ASN_TAG_SZ + MAX_LENGTH_SZ,
14855 &pkiMsg, &idx)) != 0) {
14856 break;
14857 }
14858 pkiMsgSz = (pkcs7->stream->length > 0)? pkcs7->stream->length: inSz;
14859
14860 /* Restore encOID across WANT_READ re-entries so the nonce
14861 * length validation below always sees the content-cipher
14862 * algorithm parsed in AUTHENV_3. */
14863 wc_PKCS7_StreamGetVar(pkcs7, &encOID, &blockKeySz, NULL);
14864 #endif
14865 /* get length of optional parameter sequence */
14866 if (ret == 0 && GetLength(pkiMsg, &idx, &length, pkiMsgSz) < 0) {
14867 ret = ASN_PARSE_E;
14868 }
14869
14870 /* get nonce from octet string */
14871 if (ret == 0 &&
14872 GetOctetString(pkiMsg, &idx, &nonceSz, pkiMsgSz) < 0) {
14873 ret = ASN_PARSE_E;
14874 }
14875
14876 if (ret == 0 && nonceSz > (int)sizeof(nonce)) {
14877 WOLFSSL_MSG("AuthEnvelopedData nonce too large for buffer");
14878 ret = ASN_PARSE_E;
14879 }
14880
14881 /* Enforce algorithm-specific nonce length bounds at the parser
14882 * layer so malformed lengths (notably zero-length, which would
14883 * catastrophically break AEAD uniqueness on HW backends that
14884 * skip their own checks) cannot reach the cipher engine.
14885 * - AES-GCM in CMS: RFC 5084 Sec. 3.2 mandates a 12-octet IV.
14886 * - AES-CCM: RFC 3610 Sec. 2.3 requires 7..13 octets.
14887 * Any other encOID here is a parser-state invariant violation. */
14888 if (ret == 0) {
14889 int nonceMin = 0, nonceMax = 0;
14890 switch (encOID) {
14891 #ifdef HAVE_AESGCM
14892 case AES128GCMb:
14893 case AES192GCMb:
14894 case AES256GCMb:
14895 nonceMin = GCM_NONCE_MID_SZ;
14896 nonceMax = GCM_NONCE_MID_SZ;
14897 break;
14898 #endif
14899 #ifdef HAVE_AESCCM
14900 case AES128CCMb:
14901 case AES192CCMb:
14902 case AES256CCMb:
14903 nonceMin = CCM_NONCE_MIN_SZ;
14904 nonceMax = CCM_NONCE_MAX_SZ;
14905 break;
14906 #endif
14907 default:
14908 WOLFSSL_MSG(
14909 "AuthEnvelopedData unexpected content cipher");
14910 ret = ALGO_ID_E;
14911 break;
14912 }
14913 if (ret == 0 &&
14914 (nonceSz < nonceMin || nonceSz > nonceMax)) {
14915 WOLFSSL_MSG(
14916 "AuthEnvelopedData nonce length invalid for cipher");
14917 ret = ASN_PARSE_E;
14918 }
14919 }
14920
14921 if (ret == 0) {
14922 XMEMCPY(nonce, &pkiMsg[idx], (word32)nonceSz);
14923 idx += (word32)nonceSz;
14924 }
14925
14926 /* get mac size, also stored in OPTIONAL parameter of AlgoID */
14927 if (ret == 0 && GetMyVersion(pkiMsg, &idx, &macSz, pkiMsgSz) < 0) {
14928 ret = ASN_PARSE_E;
14929 }
14930 if (ret == 0 && (macSz <= 0 || macSz > WC_AES_BLOCK_SIZE)) {
14931 WOLFSSL_MSG("AuthEnvelopedData invalid MAC length");
14932 ret = ASN_PARSE_E;
14933 }
14934
14935 if (ret == 0) {
14936 explicitOctet = 0;
14937 localIdx = idx;
14938 if (GetASNTag(pkiMsg, &localIdx, &tag, pkiMsgSz) == 0 &&
14939 tag == (ASN_CONTEXT_SPECIFIC | ASN_CONSTRUCTED | 0))
14940 explicitOctet = 1;
14941
14942 /* read encryptedContent, cont[0] */
14943 ret = GetASNTag(pkiMsg, &idx, &tag, pkiMsgSz);
14944 }
14945
14946 if (ret == 0 &&
14947 tag != (ASN_CONTEXT_SPECIFIC | 0) &&
14948 tag != (ASN_CONTEXT_SPECIFIC | ASN_CONSTRUCTED | 0)) {
14949 ret = ASN_PARSE_E;
14950 }
14951
14952 if (ret == 0 && GetLength_ex(pkiMsg, &idx, &encryptedContentSz,
14953 pkiMsgSz, 0) <= 0) {
14954 ret = ASN_PARSE_E;
14955 }
14956
14957 if (explicitOctet) {
14958 if (ret == 0 && GetASNTag(pkiMsg, &idx, &tag, pkiMsgSz) < 0) {
14959 ret = ASN_PARSE_E;
14960 }
14961 if (ret == 0 && tag != ASN_OCTET_STRING) {
14962 ret = ASN_PARSE_E;
14963 }
14964
14965 if (ret == 0 && GetLength(pkiMsg, &idx, &encryptedContentSz,
14966 pkiMsgSz) <= 0) {
14967 ret = ASN_PARSE_E;
14968 }
14969 }
14970
14971 if (ret < 0)
14972 break;
14973
14974 #ifndef NO_PKCS7_STREAM
14975 if ((ret = wc_PKCS7_StreamEndCase(pkcs7, &tmpIdx, &idx)) != 0) {
14976 break;
14977 }
14978
14979 /* store nonce and macSz for later */
14980 pkcs7->stream->icvSz = (word32)macSz;
14981 if (nonceSz > 0) {
14982 pkcs7->stream->nonceSz = (word32)nonceSz;
14983 pkcs7->stream->nonce = (byte*)XMALLOC((word32)nonceSz,
14984 pkcs7->heap, DYNAMIC_TYPE_PKCS7);
14985 if (pkcs7->stream->nonce == NULL) {
14986 ret = MEMORY_E;
14987 break;
14988 }
14989 else {
14990 XMEMCPY(pkcs7->stream->nonce, nonce, (word32)nonceSz);
14991 }
14992 }
14993
14994 pkcs7->stream->expected = (word32)encryptedContentSz +
14995 MAX_LENGTH_SZ + ASN_TAG_SZ + ASN_TAG_SZ;
14996 wc_PKCS7_StreamStoreVar(pkcs7, encOID, blockKeySz,
14997 encryptedContentSz);
14998 #endif
14999
15000 wc_PKCS7_ChangeState(pkcs7, WC_PKCS7_AUTHENV_5);
15001 FALL_THROUGH;
15002
15003 case WC_PKCS7_AUTHENV_5:
15004 #ifndef NO_PKCS7_STREAM
15005 if ((ret = wc_PKCS7_AddDataToStream(pkcs7, in, inSz,
15006 pkcs7->stream->expected, &pkiMsg, &idx)) != 0) {
15007 break;
15008 }
15009 pkiMsgSz = (pkcs7->stream->length > 0)? pkcs7->stream->length: inSz;
15010
15011 wc_PKCS7_StreamGetVar(pkcs7, &encOID, &blockKeySz,
15012 &encryptedContentSz);
15013 #else
15014 pkiMsgSz = inSz;
15015 #endif
15016
15017 if (expBlockSz == 0) {
15018 #ifndef NO_PKCS7_STREAM
15019 #endif
15020 if (encOID == 0)
15021 expBlockSz = 1;
15022 else {
15023 expBlockSz = wc_PKCS7_GetOIDBlockSize((int)encOID);
15024 if (expBlockSz < 0) {
15025 ret = expBlockSz;
15026 break;
15027 } else if (expBlockSz == 0)
15028 expBlockSz = 1;
15029 }
15030 }
15031
15032 /* AES-GCM/CCM does NOT require padding for plaintext content or
15033 * AAD inputs RFC 5084 section 3.1 and 3.2, but we must alloc
15034 * full blocks to ensure crypto only gets full blocks */
15035 encryptedAllocSz = (encryptedContentSz % expBlockSz) ?
15036 encryptedContentSz + expBlockSz -
15037 (encryptedContentSz % expBlockSz) :
15038 encryptedContentSz;
15039 encryptedContent = (byte*)XMALLOC((word32)encryptedAllocSz,
15040 pkcs7->heap, DYNAMIC_TYPE_PKCS7);
15041 if (ret == 0 && encryptedContent == NULL) {
15042 ret = MEMORY_E;
15043 }
15044
15045 if (ret == 0) {
15046 word32 tmpSum;
15047 if (!WC_SAFE_SUM_WORD32(idx, (word32)encryptedContentSz,
15048 tmpSum) ||
15049 tmpSum > pkiMsgSz) {
15050 ret = BUFFER_E;
15051 break;
15052 } else {
15053 XMEMCPY(encryptedContent, &pkiMsg[idx],
15054 (word32)encryptedContentSz);
15055 idx += (word32)encryptedContentSz;
15056 }
15057 }
15058 #ifndef NO_PKCS7_STREAM
15059 pkcs7->stream->bufferPt = encryptedContent;
15060 #endif
15061
15062 /* may have IMPLICIT [1] authenticatedAttributes */
15063 localIdx = idx;
15064 if (ret == 0 && GetASNTag(pkiMsg, &localIdx, &tag, pkiMsgSz) == 0 &&
15065 tag == (ASN_CONSTRUCTED | ASN_CONTEXT_SPECIFIC | 1)) {
15066 encodedAttribIdx = idx;
15067 idx++;
15068
15069 if (GetLength_ex(pkiMsg, &idx, &length, pkiMsgSz, 0) <= 0) {
15070 ret = ASN_PARSE_E;
15071 }
15072
15073 #ifdef NO_PKCS7_STREAM
15074 /* In non-streaming mode, validate authenticatedAttributes
15075 * length is within the input buffer. The streaming path
15076 * handles this via wc_PKCS7_AddDataToStream instead. */
15077 if (ret == 0 &&
15078 (idx > pkiMsgSz || (word32)length > pkiMsgSz - idx)) {
15079 ret = ASN_PARSE_E;
15080 }
15081 #else
15082 pkcs7->stream->expected = (word32)length;
15083 #endif
15084 encodedAttribSz = (word32)length + (idx - encodedAttribIdx);
15085
15086 if (ret != 0)
15087 break;
15088
15089 if (encodedAttribSz > 0) {
15090 encodedAttribs = (byte*)XMALLOC(encodedAttribSz,
15091 pkcs7->heap, DYNAMIC_TYPE_PKCS7);
15092 if (encodedAttribs == NULL) {
15093 ret = MEMORY_E;
15094 break;
15095 }
15096 }
15097
15098 #ifndef NO_PKCS7_STREAM
15099 if (encodedAttribSz > 0) {
15100 pkcs7->stream->aadSz = encodedAttribSz;
15101 pkcs7->stream->aad = encodedAttribs;
15102 }
15103
15104 if ((ret = wc_PKCS7_StreamEndCase(pkcs7, &tmpIdx, &idx)) != 0) {
15105 break;
15106 }
15107 #endif
15108 wc_PKCS7_ChangeState(pkcs7, WC_PKCS7_AUTHENV_ATRB);
15109 }
15110 else {
15111 #ifndef NO_PKCS7_STREAM
15112 if ((ret = wc_PKCS7_StreamEndCase(pkcs7, &tmpIdx, &idx)) != 0) {
15113 break;
15114 }
15115 pkcs7->stream->expected = MAX_LENGTH_SZ + ASN_TAG_SZ;
15116 #endif
15117 wc_PKCS7_ChangeState(pkcs7, WC_PKCS7_AUTHENV_ATRBEND);
15118 goto authenv_atrbend; /* jump over attribute cases */
15119 }
15120 FALL_THROUGH;
15121
15122 case WC_PKCS7_AUTHENV_ATRB:
15123 #ifndef NO_PKCS7_STREAM
15124 if ((ret = wc_PKCS7_AddDataToStream(pkcs7, in, inSz,
15125 pkcs7->stream->expected, &pkiMsg, &idx)) != 0) {
15126 return ret;
15127 }
15128
15129 length = (int)pkcs7->stream->expected;
15130 encodedAttribs = pkcs7->stream->aad;
15131 #endif
15132
15133 /* save pointer and length */
15134 authAttrib = &pkiMsg[idx];
15135 authAttribSz = length;
15136
15137 {
15138 word32 ofst;
15139
15140 /* From RFC5083, "For the purpose of constructing the
15141 * AAD, the IMPLICIT [1] tag in the authAttrs field is
15142 * not used for the DER encoding: rather a universal SET
15143 * OF tag is used. */
15144 ofst = SetSet((word32)length, encodedAttribs);
15145
15146 XMEMCPY(encodedAttribs + ofst, authAttrib,
15147 (word32)authAttribSz);
15148 }
15149
15150 /* ignoring the size returned, we know it is
15151 * idx - encodedAttribIdx from parsing what's given */
15152
15153 if (ret == 0 && wc_PKCS7_ParseAttribs(pkcs7, authAttrib,
15154 authAttribSz) < 0) {
15155 WOLFSSL_MSG("Error parsing authenticated attributes");
15156 ret = ASN_PARSE_E;
15157 break;
15158 }
15159
15160 idx += (word32)length;
15161
15162 #ifndef NO_PKCS7_STREAM
15163 if (pkcs7->stream->aadSz > 0) {
15164 XMEMCPY(pkcs7->stream->aad + (pkcs7->stream->aadSz -
15165 (word32)length), authAttrib, (word32)authAttribSz);
15166 }
15167 if ((ret = wc_PKCS7_StreamEndCase(pkcs7, &tmpIdx, &idx)) != 0) {
15168 break;
15169 }
15170 pkcs7->stream->expected = MAX_LENGTH_SZ + ASN_TAG_SZ;
15171 #endif
15172 wc_PKCS7_ChangeState(pkcs7, WC_PKCS7_AUTHENV_ATRBEND);
15173 FALL_THROUGH;
15174
15175 case WC_PKCS7_AUTHENV_ATRBEND:
15176authenv_atrbend:
15177 #ifndef NO_PKCS7_STREAM
15178 if ((ret = wc_PKCS7_AddDataToStream(pkcs7, in, inSz,
15179 pkcs7->stream->expected, &pkiMsg, &idx)) != 0) {
15180 return ret;
15181 }
15182 pkiMsgSz = (pkcs7->stream->length > 0)? pkcs7->stream->length: inSz;
15183
15184 if (pkcs7->stream->aadSz > 0) {
15185 encodedAttribSz = pkcs7->stream->aadSz;
15186 encodedAttribs = pkcs7->stream->aad;
15187 }
15188 macSz = (int)pkcs7->stream->icvSz;
15189 #endif
15190
15191
15192 localIdx = idx;
15193
15194 /* Get authTag OCTET STRING */
15195 if (ret == 0 && pkiMsg[localIdx] != ASN_OCTET_STRING) {
15196 ret = ASN_PARSE_E;
15197 }
15198 localIdx++; /* move past ASN_OCTET_STRING */
15199
15200 if (ret == 0 && GetLength_ex(pkiMsg, &localIdx, &length,
15201 pkiMsgSz, 0) < 0) {
15202 ret = ASN_PARSE_E;
15203 }
15204 authTagSz = (word32)length;
15205 if (ret == 0 && authTagSz != (word32)macSz) {
15206 WOLFSSL_MSG("AuthEnvelopedData authTag size mismatch");
15207 ret = ASN_PARSE_E;
15208 }
15209 if (ret == 0 &&
15210 (encOID == AES128GCMb || encOID == AES192GCMb ||
15211 encOID == AES256GCMb) &&
15212 authTagSz < WOLFSSL_MIN_AUTH_TAG_SZ) {
15213 WOLFSSL_MSG("AuthEnvelopedData GCM authTag too small");
15214 ret = ASN_PARSE_E;
15215 }
15216
15217 #ifndef NO_PKCS7_STREAM
15218 /* there might not be enough data for the auth tag too */
15219 if (ret == 0) {
15220 if ((authTagSz + (localIdx - idx)) > pkcs7->stream->expected &&
15221 (authTagSz + (localIdx - idx)) > pkiMsgSz) {
15222 pkcs7->stream->expected = authTagSz +
15223 (localIdx - idx);
15224 if ((ret = wc_PKCS7_AddDataToStream(pkcs7, in, inSz,
15225 pkcs7->stream->expected, &pkiMsg, &idx)) != 0) {
15226 return ret;
15227 }
15228 }
15229 }
15230 #endif
15231 idx = localIdx;
15232
15233 if (ret == 0 && authTagSz > (word32)sizeof(authTag)) {
15234 WOLFSSL_MSG("AuthEnvelopedData authTag too large for buffer");
15235 ret = ASN_PARSE_E;
15236 }
15237
15238 if (ret == 0) {
15239 XMEMCPY(authTag, &pkiMsg[idx], authTagSz);
15240 idx += authTagSz;
15241 }
15242
15243 if (ret < 0)
15244 break;
15245
15246 #ifndef NO_PKCS7_STREAM
15247 if ((ret = wc_PKCS7_StreamEndCase(pkcs7, &tmpIdx, &idx)) != 0) {
15248 break;
15249 }
15250 pkcs7->stream->expected = (pkcs7->stream->maxLen -
15251 pkcs7->stream->totalRd) + pkcs7->stream->length;
15252
15253
15254 /* store tag for later */
15255 if (authTagSz > 0) {
15256 pkcs7->stream->tagSz = authTagSz;
15257 pkcs7->stream->tag = (byte*)XMALLOC(authTagSz,
15258 pkcs7->heap, DYNAMIC_TYPE_PKCS7);
15259 if (pkcs7->stream->tag == NULL) {
15260 ret = MEMORY_E;
15261 break;
15262 }
15263 else {
15264 XMEMCPY(pkcs7->stream->tag, authTag, authTagSz);
15265 }
15266 }
15267
15268 #endif
15269 wc_PKCS7_ChangeState(pkcs7, WC_PKCS7_AUTHENV_6);
15270 FALL_THROUGH;
15271
15272 case WC_PKCS7_AUTHENV_6:
15273 #ifndef NO_PKCS7_STREAM
15274 if ((ret = wc_PKCS7_AddDataToStream(pkcs7, in, inSz,
15275 pkcs7->stream->expected, &pkiMsg, &idx)) != 0) {
15276 break;
15277 }
15278
15279 /* restore all variables needed */
15280 if (pkcs7->stream->nonceSz > 0) {
15281 nonceSz = (int)pkcs7->stream->nonceSz;
15282 if (nonceSz > GCM_NONCE_MID_SZ) {
15283 WOLFSSL_MSG("PKCS7 saved nonce is too large");
15284 ret = BUFFER_E;
15285 break;
15286 }
15287 else {
15288 XMEMCPY(nonce, pkcs7->stream->nonce, (word32)nonceSz);
15289 }
15290 }
15291
15292 if (pkcs7->stream->tagSz > 0) {
15293 authTagSz = pkcs7->stream->tagSz;
15294 if (authTagSz > WC_AES_BLOCK_SIZE) {
15295 WOLFSSL_MSG("PKCS7 saved tag is too large");
15296 ret = BUFFER_E;
15297 break;
15298 }
15299 else {
15300 XMEMCPY(authTag, pkcs7->stream->tag, authTagSz);
15301 }
15302 }
15303
15304 if (pkcs7->stream->aadSz > 0) {
15305 encodedAttribSz = pkcs7->stream->aadSz;
15306 encodedAttribs = pkcs7->stream->aad;
15307 }
15308
15309 wc_PKCS7_StreamGetVar(pkcs7, &encOID, &blockKeySz,
15310 &encryptedContentSz);
15311 encryptedContent = pkcs7->stream->bufferPt;
15312 decryptedKey = pkcs7->stream->key;
15313 #endif
15314
15315 /* decrypt encryptedContent */
15316 ret = wc_PKCS7_DecryptContent(pkcs7, encOID, decryptedKey,
15317 (word32)blockKeySz, nonce, nonceSz, encodedAttribs,
15318 encodedAttribSz, authTag, authTagSz,
15319 encryptedContent, encryptedContentSz, encryptedContent,
15320 pkcs7->devId, pkcs7->heap);
15321 if (ret != 0) {
15322 XFREE(encryptedContent, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
15323 return ret;
15324 }
15325
15326 if (encodedAttribs != NULL) {
15327 XFREE(encodedAttribs, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
15328 encodedAttribs = NULL;
15329 #ifndef NO_PKCS7_STREAM
15330 pkcs7->stream->aad = NULL;
15331 #endif
15332 }
15333
15334 /* copy plaintext to output */
15335 if ((word32)encryptedContentSz > outputSz) {
15336 ret = BUFFER_E;
15337 break;
15338 }
15339 XMEMCPY(output, encryptedContent, (word32)encryptedContentSz);
15340
15341 /* free memory, zero out keys */
15342 ForceZero(encryptedContent, (word32)encryptedContentSz);
15343 XFREE(encryptedContent, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
15344 encryptedContent = NULL;
15345 ForceZero(decryptedKey, MAX_ENCRYPTED_KEY_SZ);
15346 XFREE(decryptedKey, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
15347 decryptedKey = NULL;
15348 #ifndef NO_PKCS7_STREAM
15349 pkcs7->stream->key = NULL;
15350 #endif
15351 ret = encryptedContentSz;
15352 #ifndef NO_PKCS7_STREAM
15353 wc_PKCS7_ResetStream(pkcs7);
15354 #endif
15355 wc_PKCS7_ChangeState(pkcs7, WC_PKCS7_START);
15356 break;
15357 default:
15358 WOLFSSL_MSG("Unknown PKCS7 state");
15359 ret = BAD_FUNC_ARG;
15360 }
15361
15362 if (ret != 0 && ret != WC_NO_ERR_TRACE(WC_PKCS7_WANT_READ_E)) {
15363 if (decryptedKey != NULL) {
15364 ForceZero(decryptedKey, MAX_ENCRYPTED_KEY_SZ);
15365 XFREE(decryptedKey, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
15366 decryptedKey = NULL;
15367 #ifndef NO_PKCS7_STREAM
15368 pkcs7->stream->key = NULL;
15369 #endif
15370 }
15371
15372 if (encryptedContent != NULL) {
15373 ForceZero(encryptedContent, (word32)encryptedContentSz);
15374 XFREE(encryptedContent, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
15375 encryptedContent = NULL;
15376 #ifndef NO_PKCS7_STREAM
15377 pkcs7->stream->bufferPt = NULL;
15378 #endif
15379 }
15380
15381 if (encodedAttribs != NULL) {
15382 XFREE(encodedAttribs, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
15383 encodedAttribs = NULL;
15384 #ifndef NO_PKCS7_STREAM
15385 pkcs7->stream->aad = NULL;
15386 #endif
15387 }
15388 }
15389
15390#ifndef NO_PKCS7_STREAM
15391 if (ret != 0 && ret != WC_NO_ERR_TRACE(WC_PKCS7_WANT_READ_E)) {
15392 wc_PKCS7_ResetStream(pkcs7);
15393 }
15394#endif
15395
15396 return ret;
15397
15398#else
15399 WOLFSSL_MSG("AuthEnvelopedData requires AES-GCM or AES-CCM to be enabled");
15400 (void)pkcs7;
15401 (void)in;
15402 (void)inSz;
15403 (void)output;
15404 (void)outputSz;
15405
15406 return NOT_COMPILED_IN;
15407#endif /* HAVE_AESGCM | HAVE_AESCCM */
15408}
15409
15410
15411#ifndef NO_PKCS7_ENCRYPTED_DATA
15412
15413/* build PKCS#7 encryptedData content type, return encrypted size */
15414int wc_PKCS7_EncodeEncryptedData(wc_PKCS7* pkcs7, byte* output, word32 outputSz)
15415{
15416 int ret, idx = 0;
15417 int totalSz, padSz, encryptedOutSz;
15418
15419 int contentInfoSeqSz, outerContentTypeSz, outerContentSz;
15420 byte contentInfoSeq[MAX_SEQ_SZ];
15421 byte outerContentType[MAX_ALGO_SZ];
15422 byte outerContent[MAX_SEQ_SZ];
15423
15424 int encDataSeqSz, verSz, blockSz;
15425 byte encDataSeq[MAX_SEQ_SZ];
15426 byte ver[MAX_VERSION_SZ];
15427
15428 byte* plain = NULL;
15429 byte* encryptedContent = NULL;
15430
15431 int encContentOctetSz, encContentSeqSz, contentTypeSz;
15432 int contentEncAlgoSz, ivOctetStringSz;
15433 byte encContentSeq[MAX_SEQ_SZ];
15434 byte contentType[MAX_OID_SZ];
15435 byte contentEncAlgo[MAX_ALGO_SZ];
15436 byte tmpIv[MAX_CONTENT_IV_SIZE];
15437 byte ivOctetString[MAX_OCTET_STR_SZ];
15438 byte encContentOctet[MAX_OCTET_STR_SZ];
15439
15440 byte attribSet[MAX_SET_SZ];
15441 EncodedAttrib* attribs = NULL;
15442 word32 attribsSz;
15443 word32 attribsCount;
15444 word32 attribsSetSz;
15445
15446 byte* flatAttribs = NULL;
15447
15448 if (pkcs7 == NULL || pkcs7->content == NULL || pkcs7->contentSz == 0 ||
15449 pkcs7->encryptOID == 0 || pkcs7->encryptionKey == NULL ||
15450 pkcs7->encryptionKeySz == 0)
15451 return BAD_FUNC_ARG;
15452
15453 if (output == NULL || outputSz == 0)
15454 return BAD_FUNC_ARG;
15455
15456 if (pkcs7->version == 3) {
15457 verSz = SetMyVersion(0, ver, 0);
15458 outerContentTypeSz = 0;
15459 }
15460 else {
15461 /* outer content type */
15462 ret = wc_SetContentType(ENCRYPTED_DATA, outerContentType,
15463 sizeof(outerContentType));
15464 if (ret < 0)
15465 return ret;
15466
15467 outerContentTypeSz = ret;
15468
15469 /* version, 2 if unprotectedAttrs present, 0 if absent */
15470 if (pkcs7->unprotectedAttribsSz > 0) {
15471 verSz = SetMyVersion(2, ver, 0);
15472 } else {
15473 verSz = SetMyVersion(0, ver, 0);
15474 }
15475 }
15476
15477 /* EncryptedContentInfo */
15478 ret = wc_SetContentType(pkcs7->contentOID, contentType,
15479 sizeof(contentType));
15480 if (ret < 0)
15481 return ret;
15482
15483 contentTypeSz = ret;
15484
15485 /* allocate encrypted content buffer, do PKCS#7 padding */
15486 blockSz = wc_PKCS7_GetOIDBlockSize(pkcs7->encryptOID);
15487 if (blockSz < 0)
15488 return blockSz;
15489
15490 padSz = wc_PKCS7_GetPadSize(pkcs7->contentSz, (word32)blockSz);
15491 if (padSz < 0)
15492 return padSz;
15493
15494 encryptedOutSz = (int)pkcs7->contentSz + padSz;
15495
15496 plain = (byte*)XMALLOC((word32)encryptedOutSz, pkcs7->heap,
15497 DYNAMIC_TYPE_PKCS7);
15498 if (plain == NULL)
15499 return MEMORY_E;
15500
15501 ret = wc_PKCS7_PadData(pkcs7->content, pkcs7->contentSz, plain,
15502 (word32)encryptedOutSz, (word32)blockSz);
15503 if (ret < 0) {
15504 ForceZero(plain, (word32)encryptedOutSz);
15505 XFREE(plain, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
15506 return ret;
15507 }
15508
15509 encryptedContent = (byte*)XMALLOC((word32)encryptedOutSz, pkcs7->heap,
15510 DYNAMIC_TYPE_PKCS7);
15511 if (encryptedContent == NULL) {
15512 ForceZero(plain, (word32)encryptedOutSz);
15513 XFREE(plain, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
15514 return MEMORY_E;
15515 }
15516
15517 /* put together IV OCTET STRING */
15518 ivOctetStringSz = (int)SetOctetString((word32)blockSz, ivOctetString);
15519
15520 /* build up ContentEncryptionAlgorithmIdentifier sequence,
15521 adding (ivOctetStringSz + blockSz) for IV OCTET STRING */
15522 contentEncAlgoSz = (int)SetAlgoID(pkcs7->encryptOID, contentEncAlgo,
15523 oidBlkType, ivOctetStringSz + blockSz);
15524 if (contentEncAlgoSz == 0) {
15525 XFREE(encryptedContent, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
15526 ForceZero(plain, (word32)encryptedOutSz);
15527 XFREE(plain, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
15528 return BAD_FUNC_ARG;
15529 }
15530
15531 /* encrypt content */
15532 WOLFSSL_MSG("Encrypting the content");
15533 ret = wc_PKCS7_GenerateBlock(pkcs7, NULL, tmpIv, (word32)blockSz);
15534 if (ret != 0) {
15535 XFREE(encryptedContent, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
15536 ForceZero(plain, (word32)encryptedOutSz);
15537 XFREE(plain, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
15538 return ret;
15539 }
15540
15541 ret = wc_PKCS7_EncryptContent(pkcs7, pkcs7->encryptOID,
15542 pkcs7->encryptionKey, (int)pkcs7->encryptionKeySz, tmpIv, blockSz,
15543 NULL, 0, NULL, 0, plain, encryptedOutSz, encryptedContent);
15544 if (ret != 0) {
15545 XFREE(encryptedContent, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
15546 ForceZero(plain, (word32)encryptedOutSz);
15547 XFREE(plain, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
15548 return ret;
15549 }
15550
15551 encContentOctetSz = (int)SetImplicit(ASN_OCTET_STRING, 0,
15552 (word32)encryptedOutSz, encContentOctet, 0);
15553
15554 encContentSeqSz = (int)SetSequence((word32)(contentTypeSz +
15555 contentEncAlgoSz + ivOctetStringSz + blockSz +
15556 encContentOctetSz + encryptedOutSz),
15557 encContentSeq);
15558
15559 /* optional UnprotectedAttributes */
15560 if (pkcs7->unprotectedAttribsSz != 0) {
15561
15562 if (pkcs7->unprotectedAttribs == NULL) {
15563 XFREE(encryptedContent, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
15564 ForceZero(plain, (word32)encryptedOutSz);
15565 XFREE(plain, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
15566 return BAD_FUNC_ARG;
15567 }
15568
15569 attribs = (EncodedAttrib*)XMALLOC(
15570 sizeof(EncodedAttrib) * pkcs7->unprotectedAttribsSz,
15571 pkcs7->heap, DYNAMIC_TYPE_PKCS7);
15572 if (attribs == NULL) {
15573 XFREE(encryptedContent, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
15574 ForceZero(plain, (word32)encryptedOutSz);
15575 XFREE(plain, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
15576 return MEMORY_E;
15577 }
15578
15579 attribsCount = pkcs7->unprotectedAttribsSz;
15580 attribsSz = (word32)EncodeAttributes(attribs,
15581 (int)pkcs7->unprotectedAttribsSz,
15582 pkcs7->unprotectedAttribs,
15583 (int)pkcs7->unprotectedAttribsSz);
15584
15585 if (attribsSz > 0) {
15586 flatAttribs = (byte*)XMALLOC(attribsSz, pkcs7->heap,
15587 DYNAMIC_TYPE_PKCS7);
15588 if (flatAttribs == NULL) {
15589 XFREE(attribs, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
15590 XFREE(encryptedContent, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
15591 ForceZero(plain, (word32)encryptedOutSz);
15592 XFREE(plain, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
15593 return MEMORY_E;
15594 }
15595
15596 ret = FlattenAttributes(pkcs7, flatAttribs, attribs,
15597 (int)attribsCount);
15598 if (ret != 0) {
15599 XFREE(attribs, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
15600 XFREE(encryptedContent, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
15601 ForceZero(plain, (word32)encryptedOutSz);
15602 XFREE(plain, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
15603 XFREE(flatAttribs, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
15604 return ret;
15605 }
15606 }
15607
15608 attribsSetSz = SetImplicit(ASN_SET, 1, attribsSz, attribSet, 0);
15609
15610 } else {
15611 attribsSz = 0;
15612 attribsSetSz = 0;
15613 }
15614
15615 /* keep track of sizes for outer wrapper layering */
15616 totalSz = verSz + encContentSeqSz + contentTypeSz + contentEncAlgoSz +
15617 ivOctetStringSz + blockSz + encContentOctetSz + encryptedOutSz +
15618 (int)attribsSz + (int)attribsSetSz;
15619
15620 /* EncryptedData */
15621 encDataSeqSz = (int)SetSequence((word32)totalSz, encDataSeq);
15622 totalSz += encDataSeqSz;
15623
15624 if (pkcs7->version != 3) {
15625 /* outer content */
15626 outerContentSz = (int)SetExplicit(0, (word32)totalSz, outerContent, 0);
15627 totalSz += outerContentTypeSz;
15628 totalSz += outerContentSz;
15629 /* ContentInfo */
15630 contentInfoSeqSz = (int)SetSequence((word32)totalSz, contentInfoSeq);
15631 totalSz += contentInfoSeqSz;
15632 } else {
15633 contentInfoSeqSz = 0;
15634 outerContentSz = 0;
15635 }
15636
15637 if (totalSz > (int)outputSz) {
15638 WOLFSSL_MSG("PKCS#7 output buffer too small");
15639 XFREE(attribs, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
15640 XFREE(flatAttribs, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
15641 XFREE(encryptedContent, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
15642 ForceZero(plain, (word32)encryptedOutSz);
15643 XFREE(plain, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
15644 return BUFFER_E;
15645 }
15646
15647 XMEMCPY(output + idx, contentInfoSeq, (word32)contentInfoSeqSz);
15648 idx += contentInfoSeqSz;
15649 XMEMCPY(output + idx, outerContentType, (word32)outerContentTypeSz);
15650 idx += outerContentTypeSz;
15651 XMEMCPY(output + idx, outerContent, (word32)outerContentSz);
15652 idx += outerContentSz;
15653 XMEMCPY(output + idx, encDataSeq, (word32)encDataSeqSz);
15654 idx += encDataSeqSz;
15655 XMEMCPY(output + idx, ver, (word32)verSz);
15656 idx += verSz;
15657 XMEMCPY(output + idx, encContentSeq, (word32)encContentSeqSz);
15658 idx += encContentSeqSz;
15659 XMEMCPY(output + idx, contentType, (word32)contentTypeSz);
15660 idx += contentTypeSz;
15661 XMEMCPY(output + idx, contentEncAlgo, (word32)contentEncAlgoSz);
15662 idx += contentEncAlgoSz;
15663 XMEMCPY(output + idx, ivOctetString, (word32)ivOctetStringSz);
15664 idx += ivOctetStringSz;
15665 XMEMCPY(output + idx, tmpIv, (word32)blockSz);
15666 idx += blockSz;
15667 XMEMCPY(output + idx, encContentOctet, (word32)encContentOctetSz);
15668 idx += encContentOctetSz;
15669 XMEMCPY(output + idx, encryptedContent, (word32)encryptedOutSz);
15670 idx += encryptedOutSz;
15671
15672 if (pkcs7->unprotectedAttribsSz != 0) {
15673 XMEMCPY(output + idx, attribSet, attribsSetSz);
15674 idx += (int)attribsSetSz;
15675 if (attribsSz > 0) {
15676 XMEMCPY(output + idx, flatAttribs, attribsSz);
15677 idx += (int)attribsSz;
15678 }
15679 }
15680
15681 XFREE(attribs, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
15682 XFREE(flatAttribs, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
15683 XFREE(encryptedContent, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
15684 ForceZero(plain, (word32)encryptedOutSz);
15685 XFREE(plain, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
15686
15687 return idx;
15688}
15689
15690
15691/* decode and store unprotected attributes in PKCS7->decodedAttrib. Return
15692 * 0 on success, negative on error. User must call wc_PKCS7_Free(). */
15693static int wc_PKCS7_DecodeUnprotectedAttributes(wc_PKCS7* pkcs7, byte* pkiMsg,
15694 word32 pkiMsgSz, word32* inOutIdx)
15695{
15696 int ret, attribLen;
15697 word32 idx;
15698 byte tag;
15699
15700 if (pkcs7 == NULL || pkiMsg == NULL ||
15701 pkiMsgSz == 0 || inOutIdx == NULL)
15702 return BAD_FUNC_ARG;
15703
15704 idx = *inOutIdx;
15705
15706 if (GetASNTag(pkiMsg, &idx, &tag, pkiMsgSz) < 0)
15707 return ASN_PARSE_E;
15708
15709 if (tag != (ASN_CONSTRUCTED | ASN_CONTEXT_SPECIFIC | 1))
15710 return ASN_PARSE_E;
15711
15712 if (GetLength(pkiMsg, &idx, &attribLen, pkiMsgSz) < 0)
15713 return ASN_PARSE_E;
15714
15715 /* loop through attributes */
15716 if ((ret = wc_PKCS7_ParseAttribs(pkcs7, pkiMsg + idx, attribLen)) < 0) {
15717 return ret;
15718 }
15719
15720 *inOutIdx = idx;
15721
15722 return 0;
15723}
15724
15725
15726/* unwrap and decrypt PKCS#7/CMS encrypted-data object, returned decoded size */
15727int wc_PKCS7_DecodeEncryptedData(wc_PKCS7* pkcs7, byte* in, word32 inSz,
15728 byte* output, word32 outputSz)
15729{
15730 int ret = 0, version = 0, length = 0, haveAttribs = 0;
15731 word32 idx = 0;
15732
15733#ifndef NO_PKCS7_STREAM
15734 word32 tmpIdx = 0;
15735#endif
15736 word32 contentType = 0, encOID = 0;
15737
15738 int expBlockSz = 0;
15739 byte tmpIvBuf[MAX_CONTENT_IV_SIZE];
15740 byte *tmpIv = tmpIvBuf;
15741
15742 int encryptedContentSz = 0;
15743 byte padLen = 0;
15744 byte* encryptedContent = NULL;
15745
15746 byte* pkiMsg = in;
15747 word32 pkiMsgSz = inSz;
15748 byte tag = 0;
15749 byte padCheck = 0;
15750 int padIndex;
15751
15752 if (pkcs7 == NULL ||
15753 ((pkcs7->encryptionKey == NULL || pkcs7->encryptionKeySz == 0) &&
15754 pkcs7->decryptionCb == NULL))
15755 return BAD_FUNC_ARG;
15756
15757 if (pkiMsg == NULL || pkiMsgSz == 0 ||
15758 output == NULL || outputSz == 0)
15759 return BAD_FUNC_ARG;
15760
15761#ifndef NO_PKCS7_STREAM
15762 (void)tmpIv; /* help out static analysis */
15763 if (pkcs7->stream == NULL) {
15764 if ((ret = wc_PKCS7_CreateStream(pkcs7)) != 0) {
15765 return ret;
15766 }
15767 }
15768#endif
15769
15770 switch (pkcs7->state) {
15771 case WC_PKCS7_START:
15772#ifndef NO_PKCS7_STREAM
15773 if ((ret = wc_PKCS7_AddDataToStream(pkcs7, in, inSz, MAX_SEQ_SZ +
15774 MAX_ALGO_SZ, &pkiMsg, &idx)) != 0) {
15775 return ret;
15776 }
15777
15778 if ((ret = wc_PKCS7_SetMaxStream(pkcs7, in, inSz)) != 0) {
15779 return ret;
15780 }
15781 pkiMsgSz = (pkcs7->stream->length > 0)? pkcs7->stream->length: inSz;
15782#endif
15783
15784 if (GetSequence_ex(pkiMsg, &idx, &length, pkiMsgSz,
15785 NO_USER_CHECK) < 0)
15786 ret = ASN_PARSE_E;
15787
15788 if (pkcs7->version != 3) { /* ContentInfo not in firmware bundles */
15789 /* read past ContentInfo, verify type is encrypted-data */
15790 if (ret == 0 && wc_GetContentType(pkiMsg, &idx, &contentType,
15791 pkiMsgSz) < 0)
15792 ret = ASN_PARSE_E;
15793
15794 if (ret == 0 && contentType != ENCRYPTED_DATA) {
15795 WOLFSSL_MSG("PKCS#7 input not of type EncryptedData");
15796 ret = PKCS7_OID_E;
15797 }
15798 }
15799 if (ret != 0) break;
15800#ifndef NO_PKCS7_STREAM
15801 if ((ret = wc_PKCS7_StreamEndCase(pkcs7, &tmpIdx, &idx)) != 0) {
15802 break;
15803 }
15804#endif
15805 wc_PKCS7_ChangeState(pkcs7, WC_PKCS7_STAGE2);
15806 FALL_THROUGH;
15807 /* end of stage 1 */
15808
15809 case WC_PKCS7_STAGE2:
15810#ifndef NO_PKCS7_STREAM
15811 if ((ret = wc_PKCS7_AddDataToStream(pkcs7, in, inSz,
15812 MAX_LENGTH_SZ + MAX_SEQ_SZ + ASN_TAG_SZ, &pkiMsg,
15813 &idx)) != 0) {
15814 return ret;
15815 }
15816 pkiMsgSz = (pkcs7->stream->length > 0)? pkcs7->stream->length: inSz;
15817#endif
15818 if (pkcs7->version != 3) {
15819 if (ret == 0 && GetASNTag(pkiMsg, &idx, &tag, pkiMsgSz) < 0)
15820 ret = ASN_PARSE_E;
15821 if (ret == 0 && tag !=
15822 (ASN_CONSTRUCTED | ASN_CONTEXT_SPECIFIC | 0))
15823 ret = ASN_PARSE_E;
15824
15825 if (ret == 0 && GetLength_ex(pkiMsg, &idx, &length, pkiMsgSz,
15826 NO_USER_CHECK) < 0)
15827 ret = ASN_PARSE_E;
15828
15829 /* remove EncryptedData and version */
15830 if (ret == 0 && GetSequence_ex(pkiMsg, &idx, &length, pkiMsgSz,
15831 NO_USER_CHECK) < 0)
15832 ret = ASN_PARSE_E;
15833 }
15834
15835 if (ret != 0) break;
15836#ifndef NO_PKCS7_STREAM
15837 if ((ret = wc_PKCS7_StreamEndCase(pkcs7, &tmpIdx, &idx)) != 0) {
15838 break;
15839 }
15840#endif
15841 wc_PKCS7_ChangeState(pkcs7, WC_PKCS7_STAGE3);
15842 FALL_THROUGH;
15843 /* end of stage 2 */
15844
15845 case WC_PKCS7_STAGE3:
15846#ifndef NO_PKCS7_STREAM
15847 if ((ret = wc_PKCS7_AddDataToStream(pkcs7, in, inSz,
15848 MAX_VERSION_SZ + MAX_SEQ_SZ + MAX_ALGO_SZ * 2,
15849 &pkiMsg, &idx)) != 0) {
15850 return ret;
15851 }
15852 pkiMsgSz = (pkcs7->stream->length > 0)? pkcs7->stream->length: inSz;
15853#endif
15854 /* get version, check later */
15855 haveAttribs = 0;
15856 if (ret == 0 && GetMyVersion(pkiMsg, &idx, &version, pkiMsgSz) < 0)
15857 ret = ASN_PARSE_E;
15858
15859 /* remove EncryptedContentInfo */
15860 if (ret == 0 && GetSequence_ex(pkiMsg, &idx, &length, pkiMsgSz,
15861 NO_USER_CHECK) < 0)
15862 ret = ASN_PARSE_E;
15863
15864 if (ret == 0 && wc_GetContentType(pkiMsg, &idx, &contentType,
15865 pkiMsgSz) < 0)
15866 ret = ASN_PARSE_E;
15867
15868 if (ret == 0) {
15869 pkcs7->contentOID = (int)contentType;
15870 }
15871
15872 if (ret == 0 && (ret = GetAlgoId(pkiMsg, &idx, &encOID, oidBlkType,
15873 pkiMsgSz)) < 0)
15874 ret = ASN_PARSE_E;
15875 if (ret == 0 && (expBlockSz =
15876 wc_PKCS7_GetOIDBlockSize((int)encOID)) < 0)
15877 ret = expBlockSz;
15878
15879 if (ret != 0) break;
15880#ifndef NO_PKCS7_STREAM
15881 /* store expBlockSz for later */
15882 pkcs7->stream->varOne = (word32)expBlockSz;
15883 pkcs7->stream->varTwo = (int)encOID;
15884
15885 if ((ret = wc_PKCS7_StreamEndCase(pkcs7, &tmpIdx, &idx)) != 0) {
15886 break;
15887 }
15888
15889 /* store version for later */
15890 pkcs7->stream->vers = (word32)version;
15891#endif
15892 wc_PKCS7_ChangeState(pkcs7, WC_PKCS7_STAGE4);
15893 FALL_THROUGH;
15894 /* end of stage 3 */
15895
15896 /* get block cipher IV, stored in OPTIONAL parameter of AlgoID */
15897 case WC_PKCS7_STAGE4:
15898#ifndef NO_PKCS7_STREAM
15899 if ((ret = wc_PKCS7_AddDataToStream(pkcs7, in, inSz,
15900 ASN_TAG_SZ + MAX_LENGTH_SZ, &pkiMsg, &idx)) != 0) {
15901 return ret;
15902 }
15903 pkiMsgSz = (pkcs7->stream->length > 0)? pkcs7->stream->length: inSz;
15904
15905 /* restore saved variables */
15906 expBlockSz = (int)pkcs7->stream->varOne;
15907#endif
15908 if (ret == 0 && GetASNTag(pkiMsg, &idx, &tag, pkiMsgSz) < 0)
15909 ret = ASN_PARSE_E;
15910 if (ret == 0 && tag != ASN_OCTET_STRING)
15911 ret = ASN_PARSE_E;
15912
15913 if (ret == 0 && GetLength(pkiMsg, &idx, &length, pkiMsgSz) < 0)
15914 ret = ASN_PARSE_E;
15915
15916 if (ret == 0 && length != expBlockSz) {
15917 WOLFSSL_MSG(
15918 "Incorrect IV length, must be of content alg block size");
15919 ret = ASN_PARSE_E;
15920 }
15921
15922 if (ret != 0) break;
15923#ifndef NO_PKCS7_STREAM
15924 /* next chunk of data expected should have the IV */
15925 pkcs7->stream->expected = (word32)length;
15926
15927 if ((ret = wc_PKCS7_StreamEndCase(pkcs7, &tmpIdx, &idx)) != 0) {
15928 break;
15929 }
15930#endif
15931 wc_PKCS7_ChangeState(pkcs7, WC_PKCS7_STAGE5);
15932 FALL_THROUGH;
15933 /* end of stage 4 */
15934
15935 case WC_PKCS7_STAGE5:
15936#ifndef NO_PKCS7_STREAM
15937 if ((ret = wc_PKCS7_AddDataToStream(pkcs7, in, inSz,
15938 pkcs7->stream->expected + ASN_TAG_SZ +
15939 MAX_LENGTH_SZ, &pkiMsg, &idx)) != 0) {
15940 return ret;
15941 }
15942 pkiMsgSz = (pkcs7->stream->length > 0)? pkcs7->stream->length: inSz;
15943
15944 /* use IV buffer from stream structure */
15945 tmpIv = pkcs7->stream->tmpIv;
15946 length = (int)pkcs7->stream->expected;
15947#endif
15948 XMEMCPY(tmpIv, &pkiMsg[idx], (word32)length);
15949 idx += (word32)length;
15950 /* read encryptedContent, cont[0] */
15951 if (ret == 0 && GetASNTag(pkiMsg, &idx, &tag, pkiMsgSz) < 0)
15952 ret = ASN_PARSE_E;
15953 if (ret == 0 && tag != (ASN_CONTEXT_SPECIFIC | 0))
15954 ret = ASN_PARSE_E;
15955
15956 if (ret == 0 && GetLength_ex(pkiMsg, &idx, &encryptedContentSz,
15957 pkiMsgSz, NO_USER_CHECK) <= 0)
15958 ret = ASN_PARSE_E;
15959
15960#ifdef NO_PKCS7_STREAM
15961 if (ret == 0 && encryptedContentSz > (int)(pkiMsgSz - idx)) {
15962 ret = BUFFER_E;
15963 }
15964#endif
15965
15966 if (ret < 0)
15967 break;
15968#ifndef NO_PKCS7_STREAM
15969 /* next chunk of data should contain encrypted content */
15970 pkcs7->stream->varThree = encryptedContentSz;
15971 if ((ret = wc_PKCS7_StreamEndCase(pkcs7, &tmpIdx, &idx)) != 0) {
15972 break;
15973 }
15974
15975 if (pkcs7->stream->totalRd + (word32)encryptedContentSz <
15976 pkcs7->stream->maxLen) {
15977 pkcs7->stream->flagOne = 1;
15978 }
15979
15980 pkcs7->stream->expected = (pkcs7->stream->maxLen -
15981 pkcs7->stream->totalRd) + pkcs7->stream->length;
15982
15983#endif
15984 wc_PKCS7_ChangeState(pkcs7, WC_PKCS7_STAGE6);
15985 FALL_THROUGH;
15986 /* end of stage 5 */
15987
15988 case WC_PKCS7_STAGE6:
15989#ifndef NO_PKCS7_STREAM
15990 if ((ret = wc_PKCS7_AddDataToStream(pkcs7, in, inSz,
15991 pkcs7->stream->expected, &pkiMsg, &idx)) != 0) {
15992 return ret;
15993 }
15994 pkiMsgSz = (pkcs7->stream->length > 0)? pkcs7->stream->length: inSz;
15995
15996 /* restore saved variables */
15997 expBlockSz = (int)pkcs7->stream->varOne;
15998 encOID = (word32)pkcs7->stream->varTwo;
15999 encryptedContentSz = pkcs7->stream->varThree;
16000 version = (int)pkcs7->stream->vers;
16001 tmpIv = pkcs7->stream->tmpIv;
16002#endif
16003 if (encryptedContentSz <= 0 ||
16004 encryptedContentSz > (int)(pkiMsgSz - idx)) {
16005 ret = BUFFER_E;
16006 break;
16007 }
16008
16009 if (ret == 0 && (encryptedContent = (byte*)XMALLOC(
16010 (unsigned int)encryptedContentSz, pkcs7->heap,
16011 DYNAMIC_TYPE_PKCS7)) == NULL) {
16012 ret = MEMORY_E;
16013 break;
16014 }
16015
16016 if (ret == 0) {
16017 word32 tmpSum;
16018 if (!WC_SAFE_SUM_WORD32(idx, (word32)encryptedContentSz, tmpSum) ||
16019 tmpSum > pkiMsgSz) {
16020 ret = BUFFER_E;
16021 } else {
16022 XMEMCPY(encryptedContent, &pkiMsg[idx],
16023 (unsigned int)encryptedContentSz);
16024 idx += (word32)encryptedContentSz;
16025
16026 /* decrypt encryptedContent */
16027 ret = wc_PKCS7_DecryptContent(pkcs7, encOID,
16028 pkcs7->encryptionKey, pkcs7->encryptionKeySz,
16029 tmpIv, expBlockSz, NULL, 0, NULL, 0,
16030 encryptedContent, encryptedContentSz,
16031 encryptedContent, pkcs7->devId, pkcs7->heap);
16032 }
16033 if (ret != 0) {
16034 XFREE(encryptedContent, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
16035 }
16036 }
16037
16038 if (ret == 0) {
16039 padLen = encryptedContent[encryptedContentSz-1];
16040
16041 /* Constant-time padding check */
16042 padCheck |= ctMaskEq(padLen, 0);
16043 padCheck |= ctMaskGT(padLen, expBlockSz);
16044 padCheck |= ctMaskGT(padLen, encryptedContentSz);
16045 padCheck |= ctMaskGT(expBlockSz, encryptedContentSz);
16046 for (padIndex = encryptedContentSz < expBlockSz ? 0 :
16047 encryptedContentSz - expBlockSz;
16048 padIndex < encryptedContentSz; padIndex++) {
16049 byte inPad = ctMaskGTE(padIndex,
16050 encryptedContentSz - (int)padLen);
16051 padCheck |= inPad & (encryptedContent[padIndex] ^ padLen);
16052 }
16053 if (padCheck != 0) {
16054 WOLFSSL_MSG("Bad padding bytes found");
16055 ret = BUFFER_E;
16056 XFREE(encryptedContent, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
16057 break;
16058 }
16059
16060 /* copy plaintext to output */
16061 if ((word32)(encryptedContentSz - padLen) > outputSz) {
16062 XFREE(encryptedContent, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
16063 ret = BUFFER_E;
16064 break;
16065 }
16066 XMEMCPY(output, encryptedContent,
16067 (unsigned int)(encryptedContentSz - padLen));
16068
16069 /* get implicit[1] unprotected attributes, optional */
16070 wc_PKCS7_FreeDecodedAttrib(pkcs7->decodedAttrib, pkcs7->heap);
16071 pkcs7->decodedAttrib = NULL;
16072 #ifndef NO_PKCS7_STREAM
16073 if (pkcs7->stream->flagOne)
16074 #else
16075 if (idx < pkiMsgSz)
16076 #endif
16077 {
16078 haveAttribs = 1;
16079
16080 ret = wc_PKCS7_DecodeUnprotectedAttributes(pkcs7, pkiMsg,
16081 pkiMsgSz, &idx);
16082 if (ret != 0) {
16083 ForceZero(encryptedContent, (word32)encryptedContentSz);
16084 XFREE(encryptedContent, pkcs7->heap,
16085 DYNAMIC_TYPE_PKCS7);
16086 ret = ASN_PARSE_E;
16087 }
16088 }
16089 }
16090
16091 if (ret == 0) {
16092 ForceZero(encryptedContent, (word32)encryptedContentSz);
16093 XFREE(encryptedContent, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
16094
16095 /* go back and check the version now that attribs have been
16096 * processed */
16097 if (pkcs7->version == 3 && version != 0) {
16098 WOLFSSL_MSG("Wrong PKCS#7 FirmwareEncryptedData version");
16099 return ASN_VERSION_E;
16100 }
16101
16102 if (pkcs7->version != 3 &&
16103 ((haveAttribs == 0 && version != 0) ||
16104 (haveAttribs == 1 && version != 2))) {
16105 WOLFSSL_MSG("Wrong PKCS#7 EncryptedData version");
16106 return ASN_VERSION_E;
16107 }
16108 ret = encryptedContentSz - padLen;
16109 }
16110
16111 if (ret != 0) break;
16112 #ifndef NO_PKCS7_STREAM
16113 wc_PKCS7_ResetStream(pkcs7);
16114 #endif
16115 wc_PKCS7_ChangeState(pkcs7, WC_PKCS7_START);
16116 break;
16117
16118 default:
16119 WOLFSSL_MSG("Error in unknown PKCS#7 Decode Encrypted Data state");
16120 return BAD_STATE_E;
16121 }
16122
16123 if (ret != 0) {
16124 #ifndef NO_PKCS7_STREAM
16125 /* restart in error case */
16126 wc_PKCS7_ResetStream(pkcs7);
16127 #endif
16128 wc_PKCS7_ChangeState(pkcs7, WC_PKCS7_START);
16129 }
16130 return ret;
16131}
16132
16133
16134/* Function to set callback during decryption, this overrides the default
16135 * decryption function and can be used for choosing a key at run time based
16136 * on the parsed bundle so far.
16137 * returns 0 on success
16138 */
16139int wc_PKCS7_SetDecodeEncryptedCb(wc_PKCS7* pkcs7,
16140 CallbackDecryptContent decryptionCb)
16141{
16142 if (pkcs7 != NULL) {
16143 pkcs7->decryptionCb = decryptionCb;
16144 }
16145 return 0;
16146}
16147
16148
16149/* Set an optional user context that gets passed to callback
16150 * returns 0 on success
16151 */
16152int wc_PKCS7_SetDecodeEncryptedCtx(wc_PKCS7* pkcs7, void* ctx)
16153{
16154 if (pkcs7 != NULL) {
16155 pkcs7->decryptionCtx = ctx;
16156 }
16157 return 0;
16158}
16159#endif /* NO_PKCS7_ENCRYPTED_DATA */
16160
16161
16162/* Unwrap and decrypt PKCS#7/CMS EncryptedKeyPackage object, return the
16163 * decoded size. */
16164int wc_PKCS7_DecodeEncryptedKeyPackage(wc_PKCS7 * pkcs7,
16165 byte * pkiMsg, word32 pkiMsgSz, byte * output, word32 outputSz)
16166{
16167 int ret = 0;
16168 word32 pkiIndex = 0;
16169 word32 contentType = 0;
16170 int length = 0;
16171
16172 if (pkiMsg == NULL) {
16173 ret = BAD_FUNC_ARG;
16174 }
16175 /* Expect a SEQUENCE header to start the EncryptedKeyPackage
16176 * ContentInfo. */
16177 else if (GetSequence_ex(pkiMsg, &pkiIndex, &length, pkiMsgSz, 1) < 0) {
16178 ret = ASN_PARSE_E;
16179 }
16180 /* Validate the EncryptedKeyPackage OBJECT IDENTIFIER. */
16181 else if (wc_GetContentType(pkiMsg, &pkiIndex, &contentType, pkiMsgSz) < 0) {
16182 ret = ASN_PARSE_E;
16183 }
16184 else if (contentType != ENCRYPTED_KEY_PACKAGE) {
16185 WOLFSSL_MSG("PKCS#7 input not of type EncryptedKeyPackage");
16186 ret = PKCS7_OID_E;
16187 }
16188 /* Expect content [0] tag */
16189 else if (GetASNHeader(pkiMsg, ASN_CONTEXT_SPECIFIC | ASN_CONSTRUCTED,
16190 &pkiIndex, &length, pkiMsgSz) < 0) {
16191 ret = ASN_PARSE_E;
16192 }
16193 /* Check for an EncryptedKeyPackage explicit CHOICE [0] tag, indicating
16194 * an EnvelopedData subtype. */
16195 else if (GetASNHeader(pkiMsg, ASN_CONTEXT_SPECIFIC | ASN_CONSTRUCTED,
16196 &pkiIndex, &length, pkiMsgSz) >= 0) {
16197 /* An explicit CHOICE [0] tag was found. pkiIndex now should point
16198 * to the EnvelopedData ContentInfo object within the
16199 * EncryptedKeyPackage. */
16200 ret = wc_PKCS7_DecodeEnvelopedData(pkcs7, &pkiMsg[pkiIndex],
16201 pkiMsgSz - pkiIndex, output, outputSz);
16202 }
16203 else {
16204#ifndef NO_PKCS7_ENCRYPTED_DATA
16205 /* An explicit CHOICE [0] tag was not found. Check if we have an
16206 * EncryptedData blob. */
16207 ret = wc_PKCS7_DecodeEncryptedData(pkcs7, &pkiMsg[pkiIndex],
16208 pkiMsgSz - pkiIndex, output, outputSz);
16209#else
16210 ret = ASN_PARSE_E;
16211#endif
16212 }
16213
16214 return ret;
16215}
16216
16217
16218/* set stream mode for encoding and signing
16219 * returns 0 on success */
16220int wc_PKCS7_SetStreamMode(wc_PKCS7* pkcs7, byte flag,
16221 CallbackGetContent getContentCb,
16222 CallbackStreamOut streamOutCb, void* ctx)
16223{
16224 if (pkcs7 == NULL) {
16225 return BAD_FUNC_ARG;
16226 }
16227#ifdef ASN_BER_TO_DER
16228 pkcs7->encodeStream = (flag != 0);
16229 pkcs7->getContentCb = getContentCb;
16230 pkcs7->streamOutCb = streamOutCb;
16231 pkcs7->streamCtx = ctx;
16232 return 0;
16233#else
16234 (void)flag;
16235 (void)getContentCb;
16236 (void)streamOutCb;
16237 (void)ctx;
16238 return NOT_COMPILED_IN;
16239#endif
16240}
16241
16242
16243/* returns to current stream mode flag on success, negative values on fail */
16244int wc_PKCS7_GetStreamMode(wc_PKCS7* pkcs7)
16245{
16246 if (pkcs7 == NULL) {
16247 return BAD_FUNC_ARG;
16248 }
16249#ifdef ASN_BER_TO_DER
16250 return pkcs7->encodeStream;
16251#else
16252 return 0;
16253#endif
16254}
16255
16256
16257/* set option to not include certificates when creating a bundle
16258 * returns 0 on success */
16259int wc_PKCS7_SetNoCerts(wc_PKCS7* pkcs7, byte flag)
16260{
16261 if (pkcs7 == NULL) {
16262 return BAD_FUNC_ARG;
16263 }
16264 pkcs7->noCerts = (flag != 0);
16265 return 0;
16266}
16267
16268
16269/* returns the current noCerts flag value on success, negative values on fail */
16270int wc_PKCS7_GetNoCerts(wc_PKCS7* pkcs7)
16271{
16272 if (pkcs7 == NULL) {
16273 return BAD_FUNC_ARG;
16274 }
16275 return pkcs7->noCerts;
16276}
16277
16278
16279#if defined(HAVE_LIBZ) && !defined(NO_PKCS7_COMPRESSED_DATA)
16280
16281/* build PKCS#7 compressedData content type, return encrypted size */
16282int wc_PKCS7_EncodeCompressedData(wc_PKCS7* pkcs7, byte* output,
16283 word32 outputSz)
16284{
16285 byte contentInfoSeq[MAX_SEQ_SZ];
16286 byte contentInfoTypeOid[MAX_OID_SZ];
16287 byte contentInfoContentSeq[MAX_SEQ_SZ]; /* EXPLICIT [0] */
16288 byte compressedDataSeq[MAX_SEQ_SZ];
16289 byte cmsVersion[MAX_VERSION_SZ];
16290 byte compressAlgId[MAX_ALGO_SZ];
16291 byte encapContentInfoSeq[MAX_SEQ_SZ];
16292 byte contentTypeOid[MAX_OID_SZ];
16293 byte contentSeq[MAX_SEQ_SZ]; /* EXPLICIT [0] */
16294 byte contentOctetStr[MAX_OCTET_STR_SZ];
16295
16296 int ret;
16297 word32 totalSz, idx;
16298 word32 contentInfoSeqSz, contentInfoContentSeqSz, contentInfoTypeOidSz;
16299 word32 compressedDataSeqSz, cmsVersionSz, compressAlgIdSz;
16300 word32 encapContentInfoSeqSz, contentTypeOidSz, contentSeqSz;
16301 word32 contentOctetStrSz;
16302
16303 byte* compressed;
16304 word32 compressedSz;
16305
16306 if (pkcs7 == NULL || pkcs7->content == NULL || pkcs7->contentSz == 0 ||
16307 output == NULL || outputSz == 0) {
16308 return BAD_FUNC_ARG;
16309 }
16310
16311 /* allocate space for compressed content. The libz code says the compressed
16312 * buffer should be srcSz + 0.1% + 12. */
16313 compressedSz = (pkcs7->contentSz + (word32)(pkcs7->contentSz * 0.001) + 12);
16314 compressed = (byte*)XMALLOC(compressedSz, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
16315 if (compressed == NULL) {
16316 WOLFSSL_MSG("Error allocating memory for CMS compressed content");
16317 return MEMORY_E;
16318 }
16319
16320 /* compress content */
16321 ret = wc_Compress(compressed, compressedSz, pkcs7->content,
16322 pkcs7->contentSz, 0);
16323 if (ret < 0) {
16324 XFREE(compressed, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
16325 return ret;
16326 }
16327 compressedSz = (word32)ret;
16328
16329 /* eContent OCTET STRING, working backwards */
16330 contentOctetStrSz = SetOctetString(compressedSz, contentOctetStr);
16331 totalSz = contentOctetStrSz + compressedSz;
16332
16333 /* EXPLICIT [0] eContentType */
16334 contentSeqSz = SetExplicit(0, totalSz, contentSeq, 0);
16335 totalSz += contentSeqSz;
16336
16337 /* eContentType OBJECT IDENTIFIER */
16338 ret = wc_SetContentType(pkcs7->contentOID, contentTypeOid,
16339 sizeof(contentTypeOid));
16340 if (ret < 0) {
16341 XFREE(compressed, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
16342 return ret;
16343 }
16344
16345 contentTypeOidSz = ret;
16346 totalSz += contentTypeOidSz;
16347
16348 /* EncapsulatedContentInfo SEQUENCE */
16349 encapContentInfoSeqSz = SetSequence(totalSz, encapContentInfoSeq);
16350 totalSz += encapContentInfoSeqSz;
16351
16352 /* compressionAlgorithm AlgorithmIdentifier */
16353 /* Only supports zlib for compression currently:
16354 * id-alg-zlibCompress (1.2.840.113549.1.9.16.3.8) */
16355 compressAlgIdSz = SetAlgoID(ZLIBc, compressAlgId, oidCompressType, 0);
16356 totalSz += compressAlgIdSz;
16357
16358 /* version */
16359 cmsVersionSz = SetMyVersion(0, cmsVersion, 0);
16360 totalSz += cmsVersionSz;
16361
16362 /* CompressedData SEQUENCE */
16363 compressedDataSeqSz = SetSequence(totalSz, compressedDataSeq);
16364 totalSz += compressedDataSeqSz;
16365
16366 if (pkcs7->version == 3) {
16367 /* RFC 4108 section 2
16368 * When the SignedData is version 3 and eContent is compressedData then
16369 * the encoding is :
16370 * CompressedData {
16371 * version
16372 * compressionAlgorithm
16373 * encapContentInfo
16374 * }
16375 */
16376 contentInfoSeqSz = 0;
16377 contentInfoTypeOidSz = 0;
16378 contentInfoContentSeqSz = 0;
16379 }
16380 else {
16381 /* EncryptedData eContent type is encoded with:
16382 * EncryptedData {
16383 * version
16384 * EncryptedContentInfo {
16385 * contentType (i.e id-ct-compressedData)
16386 * contentEncryptionAlgorithm
16387 * octet string of CompressedData or FirmwarePkgData
16388 * }
16389 * attributes
16390 * }
16391 */
16392
16393 /* ContentInfo content EXPLICIT SEQUENCE */
16394 contentInfoContentSeqSz = SetExplicit(0, totalSz, contentInfoContentSeq,
16395 0);
16396 totalSz += contentInfoContentSeqSz;
16397
16398 ret = wc_SetContentType(COMPRESSED_DATA, contentInfoTypeOid,
16399 sizeof(contentInfoTypeOid));
16400 if (ret < 0) {
16401 XFREE(compressed, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
16402 return ret;
16403 }
16404
16405 contentInfoTypeOidSz = ret;
16406 totalSz += contentInfoTypeOidSz;
16407
16408 /* ContentInfo SEQUENCE */
16409 contentInfoSeqSz = SetSequence(totalSz, contentInfoSeq);
16410 totalSz += contentInfoSeqSz;
16411 }
16412
16413 if (outputSz < totalSz) {
16414 XFREE(compressed, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
16415 return BUFFER_E;
16416 }
16417
16418 idx = 0;
16419 if (contentInfoSeqSz > 0) {
16420 XMEMCPY(output + idx, contentInfoSeq, contentInfoSeqSz);
16421 idx += contentInfoSeqSz;
16422 }
16423 if (contentInfoTypeOidSz > 0) {
16424 XMEMCPY(output + idx, contentInfoTypeOid, contentInfoTypeOidSz);
16425 idx += contentInfoTypeOidSz;
16426 }
16427 if (contentInfoContentSeqSz > 0) {
16428 XMEMCPY(output + idx, contentInfoContentSeq, contentInfoContentSeqSz);
16429 idx += contentInfoContentSeqSz;
16430 }
16431 XMEMCPY(output + idx, compressedDataSeq, compressedDataSeqSz);
16432 idx += compressedDataSeqSz;
16433 XMEMCPY(output + idx, cmsVersion, cmsVersionSz);
16434 idx += cmsVersionSz;
16435 XMEMCPY(output + idx, compressAlgId, compressAlgIdSz);
16436 idx += compressAlgIdSz;
16437 XMEMCPY(output + idx, encapContentInfoSeq, encapContentInfoSeqSz);
16438 idx += encapContentInfoSeqSz;
16439 XMEMCPY(output + idx, contentTypeOid, contentTypeOidSz);
16440 idx += contentTypeOidSz;
16441 XMEMCPY(output + idx, contentSeq, contentSeqSz);
16442 idx += contentSeqSz;
16443 XMEMCPY(output + idx, contentOctetStr, contentOctetStrSz);
16444 idx += contentOctetStrSz;
16445 XMEMCPY(output + idx, compressed, compressedSz);
16446 idx += compressedSz;
16447
16448 XFREE(compressed, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
16449
16450 return idx;
16451}
16452
16453/* unwrap and decompress PKCS#7/CMS compressedData object,
16454 * Handles content wrapped compressed data and raw compressed data packet
16455 * returned decoded size */
16456int wc_PKCS7_DecodeCompressedData(wc_PKCS7* pkcs7, byte* pkiMsg,
16457 word32 pkiMsgSz, byte* output, word32 outputSz)
16458{
16459 int length, version, ret;
16460 word32 idx = 0, algOID, contentType;
16461 byte tag;
16462
16463 byte* decompressed;
16464 word32 decompressedSz;
16465
16466 if (pkcs7 == NULL || pkiMsg == NULL || pkiMsgSz == 0 ||
16467 output == NULL || outputSz == 0) {
16468 return BAD_FUNC_ARG;
16469 }
16470
16471 /* unwarp content surrounding if found */
16472 {
16473 word32 localIdx = idx;
16474 int err = 0;
16475
16476 /* get ContentInfo SEQUENCE */
16477 if (GetSequence(pkiMsg, &localIdx, &length, pkiMsgSz) < 0)
16478 err = ASN_PARSE_E;
16479
16480 if (err == 0 && pkcs7->version != 3) {
16481 /* get ContentInfo contentType */
16482 if (wc_GetContentType(pkiMsg, &localIdx, &contentType, pkiMsgSz)
16483 < 0)
16484 err = ASN_PARSE_E;
16485
16486 if (err == 0 && contentType != COMPRESSED_DATA)
16487 err = ASN_PARSE_E;
16488 }
16489
16490 /* get ContentInfo content EXPLICIT SEQUENCE */
16491 if (err == 0) {
16492 if (GetASNTag(pkiMsg, &localIdx, &tag, pkiMsgSz) < 0)
16493 err = ASN_PARSE_E;
16494 }
16495
16496 if (err == 0) {
16497 if (tag != (ASN_CONSTRUCTED | ASN_CONTEXT_SPECIFIC | 0))
16498 err = ASN_PARSE_E;
16499 }
16500
16501 if (err == 0) {
16502 if (GetLength(pkiMsg, &localIdx, &length, pkiMsgSz) < 0)
16503 err = ASN_PARSE_E;
16504 }
16505
16506 /* successful content unwrap, update index */
16507 if (err == 0) {
16508 idx = localIdx;
16509 }
16510 }
16511
16512 /* get CompressedData SEQUENCE */
16513 if (GetSequence(pkiMsg, &idx, &length, pkiMsgSz) < 0)
16514 return ASN_PARSE_E;
16515
16516 /* get version */
16517 if (GetMyVersion(pkiMsg, &idx, &version, pkiMsgSz) < 0)
16518 return ASN_PARSE_E;
16519
16520 if (version != 0) {
16521 WOLFSSL_MSG("CMS CompressedData version MUST be 0, but is not");
16522 return ASN_PARSE_E;
16523 }
16524
16525 /* get CompressionAlgorithmIdentifier */
16526 if (GetAlgoId(pkiMsg, &idx, &algOID, oidIgnoreType, pkiMsgSz) < 0)
16527 return ASN_PARSE_E;
16528
16529 /* Only supports zlib for compression currently:
16530 * id-alg-zlibCompress (1.2.840.113549.1.9.16.3.8) */
16531 if (algOID != ZLIBc) {
16532 WOLFSSL_MSG("CMS CompressedData only supports zlib algorithm");
16533 return ASN_PARSE_E;
16534 }
16535
16536 /* get EncapsulatedContentInfo SEQUENCE */
16537 if (GetSequence(pkiMsg, &idx, &length, pkiMsgSz) < 0)
16538 return ASN_PARSE_E;
16539
16540 /* get ContentType OID */
16541 if (wc_GetContentType(pkiMsg, &idx, &contentType, pkiMsgSz) < 0)
16542 return ASN_PARSE_E;
16543
16544 pkcs7->contentOID = contentType;
16545
16546 /* get eContent EXPLICIT SEQUENCE */
16547 if (GetASNTag(pkiMsg, &idx, &tag, pkiMsgSz) < 0)
16548 return ASN_PARSE_E;
16549
16550 if (tag != (ASN_CONSTRUCTED | ASN_CONTEXT_SPECIFIC | 0))
16551 return ASN_PARSE_E;
16552
16553 if (GetLength(pkiMsg, &idx, &length, pkiMsgSz) < 0)
16554 return ASN_PARSE_E;
16555
16556 /* get content OCTET STRING */
16557 if (GetASNTag(pkiMsg, &idx, &tag, pkiMsgSz) < 0)
16558 return ASN_PARSE_E;
16559
16560 if (tag != ASN_OCTET_STRING)
16561 return ASN_PARSE_E;
16562
16563 if (GetLength(pkiMsg, &idx, &length, pkiMsgSz) < 0)
16564 return ASN_PARSE_E;
16565
16566 /* decompress content */
16567 ret = wc_DeCompressDynamic(&decompressed, WOLFSSL_PKCS7_MAX_DECOMPRESSION,
16568 DYNAMIC_TYPE_PKCS7, &pkiMsg[idx], length, 0, pkcs7->heap);
16569 if (ret < 0) {
16570 return ret;
16571 }
16572 decompressedSz = (word32)ret;
16573
16574 /* get content */
16575 if (outputSz < decompressedSz) {
16576 WOLFSSL_MSG("CMS output buffer too small to hold decompressed data");
16577 XFREE(decompressed, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
16578 return BUFFER_E;
16579 }
16580
16581 XMEMCPY(output, decompressed, decompressedSz);
16582 XFREE(decompressed, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
16583
16584 return decompressedSz;
16585}
16586
16587#endif /* HAVE_LIBZ && !NO_PKCS7_COMPRESSED_DATA */
16588
16589static int wc_PKCS7_DecodeSymmetricKeyPackage(const byte * skp, word32 skpSz,
16590 size_t index, const byte ** out, word32 * outSz, int getKey)
16591{
16592 word32 skpIndex = 0;
16593 int length = 0;
16594 int version = 0;
16595 int ret = 0;
16596
16597 if (skp == NULL || out == NULL || outSz == NULL)
16598 ret = BAD_FUNC_ARG;
16599
16600 /* Expect a SEQUENCE header to start the SymmetricKeyPackage object. */
16601 if (ret == 0 && GetSequence(skp, &skpIndex, &length, skpSz) < 0)
16602 ret = ASN_PARSE_E;
16603
16604 /* Expect version v1 */
16605 if (ret == 0 && GetMyVersion(skp, &skpIndex, &version, skpSz) < 0)
16606 ret = ASN_PARSE_E;
16607
16608 if (ret == 0 && version != 1)
16609 ret = ASN_PARSE_E;
16610
16611 if (ret == 0 && GetASNHeader(skp, ASN_CONTEXT_SPECIFIC | ASN_CONSTRUCTED,
16612 &skpIndex, &length, skpSz) >= 0) {
16613 /* sKeyPkgAttrs [0] tag found so there are attributes present. */
16614 if (getKey != 0) {
16615 /* Key was requested, not attribute, so skip the attributes. */
16616 skpIndex += (word32)length;
16617 }
16618 else {
16619 /* sKeyPkgAttrs is present at &skp[skpIndex], length in length */
16620 ret = wc_IndexSequenceOf(&skp[skpIndex], (word32)length, index,
16621 out, outSz);
16622 }
16623 }
16624 else if (ret == 0 && getKey == 0) {
16625 /* An attribute was requested, but none are present. */
16626 ret = BAD_INDEX_E;
16627 }
16628
16629 if (ret == 0 && getKey != 0) {
16630 /* sKeys is present at &skp[skpIndex]. */
16631 ret = wc_IndexSequenceOf(&skp[skpIndex], skpSz - skpIndex, index,
16632 out, outSz);
16633 }
16634
16635 return ret;
16636}
16637
16638int wc_PKCS7_DecodeSymmetricKeyPackageAttribute(const byte * skp,
16639 word32 skpSz, size_t index, const byte ** attr, word32 * attrSz)
16640{
16641 return wc_PKCS7_DecodeSymmetricKeyPackage(skp, skpSz, index, attr, attrSz,
16642 0);
16643}
16644
16645int wc_PKCS7_DecodeSymmetricKeyPackageKey(const byte * skp,
16646 word32 skpSz, size_t index, const byte ** key, word32 * keySz)
16647{
16648 return wc_PKCS7_DecodeSymmetricKeyPackage(skp, skpSz, index, key, keySz, 1);
16649}
16650
16651int wc_PKCS7_DecodeOneSymmetricKeyAttribute(const byte * osk,
16652 word32 oskSz, size_t index, const byte ** attr, word32 * attrSz)
16653{
16654 word32 oskIndex = 0;
16655 word32 tmpIndex;
16656 int length = 0;
16657 int ret = 0;
16658
16659 if (osk == NULL || attr == NULL || attrSz == NULL)
16660 ret = BAD_FUNC_ARG;
16661
16662 /* Expect a SEQUENCE header to start the OneSymmetricKey object. */
16663 if (ret == 0 && GetSequence(osk, &oskIndex, &length, oskSz) < 0)
16664 ret = ASN_PARSE_E;
16665
16666 tmpIndex = oskIndex;
16667
16668 if (ret == 0 && GetSequence(osk, &tmpIndex, &length, oskSz) < 0) {
16669 /* sKeyAttrs is not present. */
16670 ret = BAD_INDEX_E;
16671 }
16672
16673 /* Index the sKeyAttrs SEQUENCE OF object with the given index. */
16674 if (ret == 0)
16675 ret = wc_IndexSequenceOf(&osk[oskIndex], oskSz - oskIndex, index, attr,
16676 attrSz);
16677
16678 return ret;
16679}
16680
16681int wc_PKCS7_DecodeOneSymmetricKeyKey(const byte * osk,
16682 word32 oskSz, const byte ** key, word32 * keySz)
16683{
16684 word32 oskIndex = 0;
16685 int length = 0;
16686 int ret = 0;
16687
16688 if (osk == NULL || key == NULL || keySz == NULL)
16689 ret = BAD_FUNC_ARG;
16690
16691 /* Expect a SEQUENCE header to start the OneSymmetricKey object. */
16692 if (ret == 0 && GetSequence(osk, &oskIndex, &length, oskSz) < 0)
16693 ret = ASN_PARSE_E;
16694
16695 if (ret == 0 && GetSequence(osk, &oskIndex, &length, oskSz) >= 0) {
16696 /* sKeyAttrs is present. Skip it. */
16697 oskIndex += (word32)length;
16698 }
16699
16700 if (ret == 0 && GetASNHeader(osk, ASN_OCTET_STRING, &oskIndex, &length,
16701 oskSz) < 0)
16702 ret = ASN_PARSE_E;
16703
16704 if (ret == 0) {
16705 *key = &osk[oskIndex];
16706 *keySz = (word32)length;
16707 }
16708
16709 return ret;
16710}
16711
16712#else /* HAVE_PKCS7 */
16713
16714
16715#ifdef _MSC_VER
16716 /* 4206 warning for blank file */
16717 #pragma warning(disable: 4206)
16718#endif
16719
16720
16721#endif /* HAVE_PKCS7 */